Wîkîferheng kuwiktionary https://ku.wiktionary.org/wiki/Destp%C3%AAk MediaWiki 1.47.0-wmf.12 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 ar 0 3414 6291740 6262234 2026-07-27T23:08:48Z Ghybu 1393 /* Navdêr 1 */ 6291740 wikitext text/x-wiki {{binêre herwiha/ar}} == {{ziman|ku}} == === Bilêvkirin === * (''Navdêr 1-4'') {{ku-IPA}}, ئار * (''Navdêr 5'') {{ku-IPA|'ar}}, عار === Navdêr 1 === {{ds|ard|ar}} {{ku-tewîn-nav|ar|nêr|alt.çem.yj='''ê'''r}} [[Wêne:Flour 06.jpg|thumb|ar (danê hêrayî)]] {{navdêr|ku|z=n}} # {{f|ku|xwarin}} [[toz|Toza]] [[spî]] yan [[gewr]] ya ku [[hevîr]]ê [[nan]]î jê têt çêkirin, <br>[[dexlûdan]]ê ku [[nan]] jê tê çêkirin <br>(bi taybetî yê ku bi [[aş]]î yan [[destar]]î hatiye [[hêran]] [[anku]] [[hûr]]-[[hûr]]kirin). #* {{jêder-pirtûk|ku|jêgirtin=Dedo û Nado çûn aş, '''ar''' anîn; aş dûr bû, '''ar''' hûr bû.|nivîskar=R. Drambyan|sernav=Ber bi Emrê Teze: Kitêba xwendinê zimanê kurmancî|sal=1931|rûpel=14}} ==== Bi alfabeyên din ==== * {{ku-ar|ئار}} * {{ku-kr|ар}} ==== Formên alternatîv ==== {{kol3|ku |ard |arvan<q:2> }} ==== Jê ==== {{kol3|ku|cure=Jê |bêar |bêarî |bêarîtî |bêartî |biar |biarî |biarîtî |biartî |ardar |ardarî |ardarîtî |ardartî |ardêr |ardêrî |ardêrîtî |ardêrtî |arî<q:3> }} ==== Etîmolojî ==== {{ji|ine-pro|ku|-}}: '''*el'''- ("[[hêran]]") :{{ji|ira-pro||-}}: '''*ar'''- ("[[hêran]]") ::{{ae}}: '''ar'''- ("[[hêran]]") ::{{pal}}: '''ar'''- ("[[hêran]]") ::{{ho}}: '''arr'''- ("[[hêran]]") ::{{sog}}: ''''rd''', ''''rd'rn'k''' ("arî") ::{{har}}: ''''rd''' ("ar") ::{{fa}}: '''ard''' ("ar") ::{{ku}}: '''hêr-''' ("[[hêran]]"), '''ar, ard''' ("ar") ::[[belûçî]]: '''art''' ("ar") ::[[sîvendî]]: '''arde''' ("ar") ::{{hac}}: '''har-''' ("[[hêran]]"), '''ardi''' ("ar")... ::{{zza}}: '''ard''' :{{sa}}: '''ātā''' ("ar") :{{el}}: '''aleo''' ("[[hêran]]") :{{hy}}: '''alam''' ("[[hêran]]")... :{{somerî}}: '''ara; arar''' ("[[hêran, herrişandin, aş, destarr]]")... <font style="font-size:10px">'''Çavkanî:''' [[Şablon:Cheung|Cheung p.166]]</font> | <font style="font-size:10px">'''Pokorny:''' 28 f.</font><br> <font style="font-size:10px">'''[[hevreh]]:''' [[hêran]]</font> ==== Werger ==== {{werger-ser}} * {{Z|ady}}: {{W-|ady|хьаджыгъэ}} * {{Z|af}}: {{W+|af|meel}} * {{Z|sq}}: {{W+|sq|miell|n}} * {{Z|de}}: {{W+|de|Mehl|nt}} * {{Z|alt}}: {{W-|alt|кулур}}, {{W-|alt|ун}} * {{Z|am}}: {{W-|am|ዱቄት}} * {{Z|as}}: {{W-|as|আটা}} * {{Z|ast}}: {{W-|ast|fariña|m}}, {{W-|ast|farina|m}} * {{Z|ain}}: {{W-|ain|アマㇺコホ|tr=amamkoho}} * {{Z|az}}: {{W+|az|un}} * {{Z|eu}}: {{W-|eu|irin}} * {{Z|ba}}: {{W-|ba|он}} * {{Z|bbl}}: {{W-|bbl|ჰ̡აჲრუ̆}}, {{W-|bbl|ჰ̡აჲრი̆}} * {{Z|be}}: {{W-|be|мука́|m}} * {{Z|bal}}: {{W-|bal|آڑت|tr=ářt}} * {{Z|bn}}: {{W+|bn|আটা}}, {{W-|bn|ময়দা}} * {{Z|br}}: {{W+|br|bleud|n}} * {{Z|kxd}}: {{W-|kxd|tapung}} * {{Z|bg}}: {{W+|bg|брашно́|nt}} * {{Z|my}}: {{W+|my|မှုန့်}}, {{W+|my|ဂျုံမှုန့်}} * {{Z|bua}}: {{W-|bua|гурил}} * {{Z|cs}}: {{W+|cs|mouka|m}} * {{Z|chr}}: {{W-|chr|ᎢᏌ}}, {{W-|chr|ᎤᏣᎴᏍᏓ}}, {{W-|chr|ᎢᏒ ᏩᏂᎨ}} * {{Z|ny}}: {{W-|ny|ufa}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|麵粉|tr=min6 fan2}} *: {{Z|cmn}}: {{W+|cmn|麵粉|tr=miànfěn}} * {{Z|cv}}: {{W-|cv|ҫӑнӑх}} * {{Z|dlm}}: {{W-|dlm|faraina|m}} * {{Z|da}}: {{W+|da|mel|nt}} * {{Z|dta}}: {{W-|dta|golii}} * {{Z|sce}}: {{W-|sce|ghurun}} * {{Z|egl}}: {{W-|egl|faréṅna|m}} * {{Z|id}}: {{W+|id|tepung}} * {{Z|ar}}: {{W-|ar|طَحِين|n}}, {{W+|ar|دَقِيق|n}} *: {{Z|acw}}: {{W-|acw|دَقيق|n|tr=dagīg}} *: {{Z|ary}}: {{W-|ary|دجيج|n|tr=dgig}}, {{W-|ary|طحين|n|tr=ṭḥin}} * {{Z|hy}}: {{W+|hy|ալյուր}} *: {{Z|xcl}}: {{W-|xcl|ալիւր}} * {{Z|eo}}: {{W+|eo|faruno}} * {{Z|et}}: {{W-|et|jahu}} * {{Z|evn}}: {{W-|evn|бурдук}} * {{Z|fax}}: {{W-|fax|fariña|m}} * {{Z|fa}}: {{W+|fa|آرد|tr=ârd}} * {{Z|fo}}: {{W-|fo|mjøl|nt}} * {{Z|fi}}: {{W+|fi|jauho}} * {{Z|fr}}: {{W+|fr|farine|m}} * {{Z|fur}}: {{W-|fur|farine|m}} * {{Z|stq}}: {{W-|stq|Meel}} * {{Z|fy}}: {{W-|fy|moal}} * {{Z|gd}}: {{W-|gd|flùr|n}}, {{W-|gd|min|m}} * {{Z|gl}}: {{W+|gl|fariña|m}}, {{W-|gl|óleo|n}} * {{Z|gu}}: {{W-|gu|આટો|n}}, {{W-|gu|લોટ|n}} * {{Z|ka}}: {{W-|ka|ფქვილი}} * {{Z|ht}}: {{W-|ht|farin}} * {{Z|hi}}: {{W+|hi|आटा|n}} * {{Z|nl}}: {{W+|nl|meel|nt}}, {{W+|nl|bloem|m}} * {{Z|he}}: {{W+|he|קֶמַח|n|tr=kemakh}} * {{Z|io}}: {{W+|io|farino}} * {{Z|ang}}: {{W-|ang|melu|nt}} * {{Z|enm}}: {{W-|enm|flour}}, {{W-|enm|mele}} * {{Z|en}}: {{W+|en|flour}} * {{Z|ia}}: {{W-|ia|farina}} * {{Z|ga}}: {{W-|ga|plúr|n}} *: {{Z|sga}}: {{W-|sga|men}} * {{Z|ist}}: {{W-|ist|fareîna|m}} * {{Z|it}}: {{W+|it|farina|m}} * {{Z|is}}: {{W+|is|mjöl|nt}} * {{Z|ja}}: {{W+|ja|穀粉|tr=こくふん, kokufun}}, {{W+|ja|小麦粉|tr=こむぎこ, komugi-ko}}, {{W+|ja|メリケン粉|tr=めりけんこ, meriken-ko}} * {{Z|kaw}}: {{W-|kaw|gĕlĕpung}} * {{Z|jv}}: {{W+|jv|glepung}} * {{Z|kbd}}: {{W-|kbd|хьэжыгъэ}} * {{Z|kl}}: {{W-|kl|qajuusat}} * {{Z|xal}}: {{W-|xal|һуйр}} * {{Z|kn}}: {{W+|kn|ಹಿಟ್ಟು}} * {{Z|ca}}: {{W+|ca|farina|m}} * {{Z|kgp}}: {{W-|kgp|farĩnh}} * {{Z|qu}}: {{W-|qu|ullpu}}, {{W-|qu|haku}}, {{W-|qu|kuta}} * {{Z|ky}}: {{W+|ky|ун}} * {{Z|si}}: {{W-|si|පිටි}} * {{Z|rw}}: {{W-|rw|ifu}} * {{Z|koi}}: {{W-|koi|пызь}} * {{Z|swb}}: {{W-|swb|ngano|c9|c10}} * {{Z|ko}}: {{W+|ko|밀가루}}, {{W+|ko|가루}} * {{Z|kw}}: {{W-|kw|bleus|n}} * {{Z|co}}: {{W+|co|farina|m}} * {{Z|kmv}}: {{W-|kmv|fahin}} * {{Z|pov}}: {{W-|pov|forinha}} * {{Z|vkp}}: {{W-|vkp|fari}} * {{Z|mcm}}: {{W-|mcm|farinya}} * {{Z|kum}}: {{W-|kum|ун}} * {{Z|lad}}: {{W-|lad|farina|m}} * {{Z|la}}: {{W-|la|farīna|m}} * {{Z|lv}}: {{W+|lv|milti|n-p}} * {{Z|lo}}: {{W-|lo|ແປ້ງ}} * {{Z|lzz}}: {{W-|lzz|ქუერი}} * {{Z|lij}}: {{W-|lij|faænn-a|m}} * {{Z|lt}}: {{W+|lt|miltai|n-p}} * {{Z|lmo}}: {{W-|lmo|farinna|m}} * {{Z|lb}}: {{W-|lb|Miel|nt}} * {{Z|mdh}}: {{W-|mdh|tapung}} * {{Z|mk}}: {{W-|mk|брашно|nt}} * {{Z|mg}}: {{W+|mg|koba}} * {{Z|ml}}: {{W-|ml|മാവു}} * {{Z|ms}}: {{W+|ms|tepung}} * {{Z|mt}}: {{W-|mt|dqiq|n}} * {{Z|mnc}}: {{W-|mnc|ᡠᡶᠠ}} * {{Z|mi}}: {{W+|mi|parāoa}} * {{Z|mrw}}: {{W-|mrw|tapong}}, {{W-|mrw|arina}} * {{Z|mr}}: {{W-|mr|पीठ|nt}} * {{Z|mhr}}: {{W-|mhr|ложаш}} * {{Z|hu}}: {{W+|hu|liszt}} * {{Z|ruq}}: {{W-|ruq|fărínă|m}} * {{Z|xmf}}: {{W-|xmf|ქვირი}} * {{Z|egy}}: {{W-egy|nḏ|h=nD-H_SPACE:nw-U9:Z2ss}} * {{Z|mwl}}: {{W-|mwl|farina|m}} * {{Z|moh}}: {{W-|moh|othèːseraʼ}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|гурил}} *: Mongolî: {{W-|mn|ᠭᠤᠯᠢᠷ}} * {{Z|nah}}: {{W+|nah|textli}} * {{Z|gld}}: {{W-|gld|опа}} * {{Z|nv}}: {{W-|nv|akʼáán}} * {{Z|nds}}: {{W-|nds|Meel|nt}} * {{Z|ne}}: {{W-|ne|पिठो}}, {{W-|ne|आटो}} * {{Z|nrf}}: {{W-|nrf|flieu|m}}, {{W-|nrf|flleur|m}} * {{Z|no}}: {{W-|no|mjøl|nt}} *: {{Z|no}}: {{W+|no|mel|nt}} * {{Z|oc}}: {{W+|oc|farina|m}} * {{Z|or}}: {{W-|or|ଅଟା}} * {{Z|ug}}: {{W-|ug|ئۇن}} * {{Z|uz}}: {{W+|uz|un}} * {{Z|ps}}: {{W+|ps|اوړه|n|tr=orha}} * {{Z|pms}}: {{W-|pms|farin-a|m}} * {{Z|pdt}}: {{W-|pdt|Mäl|nt}} * {{Z|pl}}: {{W+|pl|mąka|m}} * {{Z|pt}}: {{W+|pt|farinha|m}} * Puncabî: *: Şaxmuxî: {{W+|pa|آٹا|tr=āṭṭā}} *: Gurmuxî: {{W-|pa|ਆੱਟਾ|n}} * {{Z|kk}}: {{W-|kk|ұн}} * {{Z|mwr}}: {{W-|mwr|आटौ|n|tr=āṭau}} * {{Z|rhg}}: {{W-|rhg|fáki}} * {{Z|rgn}}: {{W-|rgn|faròina|m}} * {{Z|rm}}: {{W-|rm|farina|m}} * {{Z|rom}}: {{W-|rom|arro|n}} * {{Z|ro}}: {{W+|ro|făină|m}} * {{Z|ru}}: {{W+|ru|мука́}} * {{Z|sms}}: {{W-|sms|jävv}} * {{Z|sat}}: {{W-|sat|ᱯᱤᱴᱷᱟ}} * {{Z|sc}}: {{W-|sc|farína|m}} * {{Z|ceb}}: {{W-|ceb|harina}} * {{Z|scn}}: {{W+|scn|farina|m}} * {{Z|sd}}: {{W-|sd|اٽو|n|tr=aṭo|cuda=اَٽو}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|бра̏шно|nt}} *: Latînî: {{W+|sh|brȁšno|nt}} * {{Z|syc}}: {{W-|syc|ܩܡܚܐ|n|tr=qamḥɑ}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|мѫка|m}}, {{W-|cu|брашьно|nt}} *: Glagolîtîk: {{W-|cu|ⰿⱘⰽⰰ|m}}, {{W-|cu|ⰱⱃⰰⱎⱐⱀⱁ|nt}} * {{Z|sk}}: {{W+|sk|múka|m}} * {{Z|sl}}: {{W+|sl|moka|m}} * {{Z|so}}: {{W+|so|daqiiq|n}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|muka|m}} *: {{Z|hsb}}: {{W-|hsb|muka|m}}, {{W-|hsb|mučka|m}} * {{Z|es}}: {{W+|es|harina|m}} * {{Z|sva}}: {{W-|sva|ფექ}}, {{W-|sva|ფაქუ̂}} * {{Z|sv}}: {{W+|sv|mjöl|nt}} * {{Z|xsr}}: {{W-|xsr|ཕེ}} * {{Z|tg}}: {{W-|tg|орд}} * {{Z|tl}}: {{W-|tl|harina}}, {{W+|tl|arina}} * {{Z|ta}}: {{W+|ta|மாவு}} * {{Z|rif}}: {{W-|rif|arn}} * {{Z|th}}: {{W+|th|แป้ง}} * {{Z|te}}: {{W+|te|పిండి}} * {{Z|tt}}: {{W+|tt|он}} * {{Z|tr}}: {{W+|tr|un}} * {{Z|tk}}: {{W-|tk|un}}, {{W-|tk|uun}} * {{Z|bo}}: {{W-|bo|ཕྱེ}} * {{Z|tum}}: {{W-|tum|ufu}} * {{Z|tpw}}: {{W-|tpw|uí}} * {{Z|udm}}: {{W-|udm|пызь}} * {{Z|uga}}: {{W-|uga|𐎖𐎎𐎈}} * {{Z|ur}}: {{W+|ur|آٹا|n|tr=āṭā}} * {{Z|uk}}: {{W+|uk|бо́рошно|nt}}, {{W-|uk|мука́|m}} * {{Z|vec}}: {{W+|vec|fior|n}} * {{Z|vep}}: {{W-|vep|jauh}} * {{Z|vi}}: {{W+|vi|bột}}, {{W+|vi|phấn}} * {{Z|vo}}: {{W-|vo|lemeil}} * {{Z|vro}}: {{W-|vro|jauh}}, {{W-|vro|jahu}} * {{Z|vot}}: {{W-|vot|javo}} * {{Z|wa}}: {{W+|wa|farene|m}}, {{W+|wa|fleur|m}} * {{Z|cy}}: {{W+|cy|blawd|n}}, {{W+|cy|can|n}} * {{Z|wym}}: {{W-|wym|māł|nt}}, {{W-|wym|maoł|nt}} * {{Z|km}}: {{W+|km|ម្សៅ|tr=msav}}, {{W-|km|ម្សៅមី|tr=msav mii}} * {{Z|yai}}: {{W-|yai|орта}} * {{Z|yi}}: {{W-|yi|מעל|m}} * {{Z|el}}: {{W+|el|αλεύρι|nt}} *: Kevn: {{W-|grc|ἄλευρον|nt}} *: {{Z|gmy}}: {{W-|gmy|𐀕𐀩𐀄𐀫}} *: {{Z|gmy}}: {{W-|gmy|𐀎}} {{werger-bin}} :{{werger çavkanî|en|flour|beş=Ev qismê Wergerê|oldid=75768723}} === Navdêr 2 === {{navdêr|ku|z=n}} # {{f|ku|fizîk}} [[agir]], [[şewat]], [[ateş]] ==== Jê ==== {{kol3|ku|cure=Jê |arav |aravî |arî |arkuj |arkujî |arperêz |arperêzî |arperêzîtî }} ==== Etîmolojî ==== Ji {{ji|ira-pro|ku|*āθr}} < *ātar-. Hevreha belûçî {{q|bal|آس}}, sîvendî [[ūīr]]. An ji [[agir]] > *ayir > ar (wek [[soranî]] {{g|ckb|ئاور|tr=awir}} û goranî {{g|hac|ئایر|tr=ayir}}) an jî ji *aθr > *ahr > ar. ==== Werger ==== {{werger-bnr|agir}} === Navdêr 3 === {{navdêr|ku|z=n}} # [[war]], [[wargeh]], [[der]], [[cih]]: #''arê me'' (warê me) ==== Etîmolojî ==== Sivikkirina ''[[war]]''. ==== Werger ==== {{werger-ser}} {{werger-bin}} === Navdêr 4 === {{ku-tewîn-nav|ar|mê}} [[Wêne:Hectare Diagram.svg|thumb|Yek '''ar'''.]] {{navdêr|ku|z=m}} # {{maneid|ku|pîvan}} {{f|ku|metrolojî}} [[şimbil]], [[pîvan]]a [[ber]]ê tiştekî yan [[der]]ekê <br>(Her arek 100 m<sup>2</sup> ye.) ==== Sembol ==== * {{g|navz|a}} ==== Jê ==== {{kol3|ku |arî |hektar }} ==== Etîmolojî ==== Ji {{ji|fr|ku|are}}. ==== Werger ==== {{werger-ser}} * {{Z|fi}}: [[aari]] (pinta-alayksikkö) * {{Z|fr}}: {{W+|fr|are}} * {{Z|nl}}: {{W+|nl|are}} * {{Z|en}}: [[are]] (unit of area, 100 m<sup>2</sup>) * {{Z|lv}}: {{W-|lv|ārs|n}} * {{Z|pl}}: {{W+|pl|ar|n}} * {{Z|ru}}: [[ap|ар]] (ar) * {{Z|sk}}: {{W-|sk|ár|n}} * {{Z|sv}}: {{W+|sv|ar|c}} * {{Z|tr}}: {{W+|tr|ar}} {{werger-bin}} {{bend}} === Navdêr 5 === {{navdêr|ku|z=m}} # [[eyb]], [[şerm]], [[fihêtî]], [[heya]]: #: ''Ew bêar e.'' (Ew bêşerm e.) ==== Formên alternatîv ==== * {{g|ku|'ar}} ==== Bi alfabeyên din ==== * {{ku-ar|عار}} ==== Etîmolojî ==== Ji {{deyn|ar|ku|عَار}} ==== Jê ==== {{kol3|ku |bêar |bêarane |bêarî |bêarîtî |bêartî }} ==== Werger ==== {{werger-ser}} * {{Z|akl}}: {{W-|akl|huya'}} * {{Z|sq}}: {{W+|sq|turp|n}} * {{Z|de}}: {{W+|de|Scham|m}}, {{W+|de|Schande|m}} * {{Z|an}}: {{W-|an|vergüenya}} * {{Z|rup}}: {{W-|rup|arushini|m}} * {{Z|as}}: {{W-|as|লাজ}} * {{Z|ast}}: {{W-|ast|vergoña|m}}, {{W-|ast|vergüeña}}, {{W-|ast|vergüenza}}, {{W-|ast|virgüenza}}, {{W-|ast|vergonza}} * {{Z|az}}: {{W+|az|abır}}, {{W+|az|ayıb}}, {{W-|az|utanc}} * {{Z|eu}}: {{W-|eu|lotsa}} * {{Z|ba}}: {{W-|ba|оят}} * {{Z|be}}: {{W-|be|со́рам|n}}, {{W-|be|стыд|n}} * {{Z|bn}}: {{W+|bn|লজ্জা}}, {{W+|bn|শরম}} * {{Z|bcl}}: {{W-|bcl|supog}} * {{Z|bg}}: {{W+|bg|срам|n}}, {{W+|bg|свян|n}} * {{Z|ce}}: {{W-|ce|эхь}} * {{Z|cs}}: {{W+|cs|stud|n}}, {{W+|cs|hanba|m}} * {{Z|zh}}: *: {{Z|cmn}}: {{W+|cmn|羞辱|tr=xiūrǔ}}, {{W+|cmn|羞恥|tr=xiūchǐ}}, {{W+|cmn|恥辱|tr=chǐrǔ}} * {{Z|da}}: {{W+|da|skam|g}} * {{Z|egl}}: {{W-|egl|vargåggna}} * {{Z|id}}: {{W+|id|malu}} * {{Z|ar}}: {{W+|ar|خَجَل|n}} * {{Z|hy}}: {{W+|hy|ամոթ}}, {{W+|hy|խայտառակություն}} * {{Z|eo}}: {{W+|eo|honto}} * {{Z|et}}: {{W-|et|häbi}} * {{Z|fax}}: {{W-|fax|vergonza}} * {{Z|fa}}: {{W+|fa|شرم|tr=šarm}} * {{Z|fi}}: {{W+|fi|häpeä}} * {{Z|fr}}: {{W+|fr|honte|m}} * {{Z|fur}}: {{W-|fur|vergonze|m}}, {{W-|fur|vergonge|m}} * {{Z|gl}}: {{W+|gl|vergoña|m}}, {{W+|gl|vergonza|m}} * {{Z|got}}: {{W-|got|𐌹𐌳𐍅𐌴𐌹𐍄|nt}}, {{W-|got|𐌰𐌹𐍅𐌹𐍃𐌺𐌹|nt}} * {{Z|ka}}: {{W-|ka|სირცხვილი|sc=Geor}} * {{Z|hi}}: {{W+|hi|शर्म|m}}, {{W+|hi|लज्जा|m}} * {{Z|nl}}: {{W+|nl|schaamte|m}}, {{W+|nl|schande|m}} * {{Z|he}}: {{W+|he|בּוּשָׁה|m|tr=bushá}} * {{Z|io}}: {{W+|io|shamo}} * {{Z|ilo}}: {{W-|ilo|bain}} * {{Z|ang}}: {{W-|ang|sċamu|m}} * {{Z|en}}: {{W+|en|shame}} * {{Z|inh}}: {{W-|inh|эхь}} * {{Z|ga}}: {{W-|ga|náire|m}} * {{Z|ist}}: {{W-|ist|varguogna|m}} * {{Z|it}}: {{W+|it|vergogna|m}} * {{Z|is}}: {{W+|is|háðung|m}}, {{W+|is|skömm|m}} * {{Z|ja}}: {{W+|ja|恥|tr=はじ, haji}}, {{W+|ja|羞恥心|tr=しゅうちしん, shūchishin}}, {{W+|ja|面汚し|tr=つらよごし, tsurayogoshi}} * {{Z|kaw}}: {{W-|kaw|isin}} * {{Z|jv}}: {{W+|jv|isin}} * {{Z|ca}}: {{W+|ca|vergonya|m}} * {{Z|ky}}: {{W+|ky|уят}} * {{Z|ko}}: {{W+|ko|수치}} * {{Z|co}}: {{W+|co|vargogna|m}} * {{Z|ltg}}: {{W-|ltg|kauns}} * {{Z|la}}: {{W-|la|pudor|n}} * {{Z|lv}}: {{W-|lv|kauns|n}} * {{Z|lez}}: {{W-|lez|айиб}} * {{Z|ln}}: {{W-|ln|nsóni}} * {{Z|mk}}: {{W-|mk|срам|n}} * {{Z|mni}}: {{W-|mni|ꯏꯀꯥꯏ}} * {{Z|mi}}: {{W-|mi|ngaringariā}}, {{W-|mi|whakamā}}, {{W-|mi|aniutanga}}, {{W-|mi|māteatea}} * {{Z|hu}}: {{W+|hu|szégyen}} * {{Z|mwl}}: {{W-|mwl|bergonha}}, {{W-|mwl|bargonha}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|ичгүүр}} *: Mongolî: {{W-|mn|ᠢᠴᠢᠭᠦᠷᠢ}} * {{Z|nah}}: {{W-|nah|pinauia}} * {{Z|nap}}: {{W-|nap|scuorno|n}} * {{Z|no}}: {{W+|no|skam}} * {{Z|oc}}: {{W+|oc|vergonha|m}} * {{Z|os}}: {{W-|os|ӕфсӕрм}} * {{Z|ug}}: {{W-|ug|نومۇس}}, {{W-|ug|ئۇيات}} * {{Z|uz}}: {{W+|uz|or}}, {{W+|uz|nomus}}, {{W+|uz|uyat}}, {{W+|uz|sharm}} * {{Z|pag}}: {{W-|pag|baing}} * {{Z|ps}}: {{W+|ps|شرم|n|tr=šárәm}} * {{Z|pdt}}: {{W-|pdt|Schaund|m}} * {{Z|pl}}: {{W+|pl|wstyd|n}}, {{W+|pl|hańba|m}}, {{W+|pl|sromota|m}} * {{Z|pt}}: {{W+|pt|vergonha|m}} * {{Z|kk}}: {{W-|kk|ұят|sc=Cyrl}} * {{Z|ro}}: {{W+|ro|rușine|m}} * {{Z|ru}}: {{W+|ru|стыд|n}}, {{W+|ru|срам|n}}, {{W+|ru|позо́р|n}} * {{Z|sa}}: {{W+|sa|लज्जा}} * {{Z|sc}}: {{W-|sc|bergugna|m}}, {{W-|sc|bregúngia}}, {{W-|sc|birgonza}}, {{W-|sc|bregunza}}, {{W-|sc|brigunza}}, {{W-|sc|frigonza}}, {{W-|sc|vilgonza}}, {{W-|sc|bilgonza}} * {{Z|ceb}}: {{W-|ceb|kaulaw}} * {{Z|scn}}: {{W+|scn|virgogna|m}}, {{W+|scn|vrigogna}}, {{W+|scn|vriogna}}, {{W+|scn|vivrogna}}, {{W+|scn|briogna}}; {{W+|scn|russura}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|сра̑м|n}} *: Latînî: {{W+|sh|srȃm|n}}, {{W+|sh|stȋd|n}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|срамъ|n}}, {{W-|sh|сти̑д|n}} *: Glagolîtîk: {{W-|cu|ⱄⱃⰰⰿⱏ|n}} * {{Z|orv}}: {{W-|orv|соромъ|n}} * {{Z|sk}}: {{W-|sk|stud|n}}, {{W+|sk|hanba|m}} * {{Z|sl}}: {{W-|sl|sram|n}} * {{Z|es}}: {{W+|es|vergüenza|m}}, {{W+|es|acholo|n}} * {{Z|sw}}: {{W+|sw|aibu}} * {{Z|sv}}: {{W+|sv|skam|g}} * {{Z|tg}}: {{W+|tg|шарм}} * {{Z|tl}}: {{W-|tl|hiya}} * {{Z|ta}}: {{W+|ta|வெட்கம்}} * {{Z|th}}: {{W-|th|ความละอายใจ|tr=kwaam lá-aai-jai}} * {{Z|te}}: {{W+|te|సిగ్గు}} * {{Z|crh}}: {{W-|crh|ayıp}} * {{Z|tt}}: {{W+|tt|оят}} * {{Z|tet}}: {{W-|tet|moe}} * {{Z|tr}}: {{W+|tr|utanç}}, {{W+|tr|ayıp}} * {{Z|tk}}: {{W-|tk|utanç}}, {{W-|tk|uýat}} * {{Z|txb}}: {{W-|txb|kwīpe}}, {{W-|txb|yase}} * {{Z|uga}}: {{W-|uga|𐎁𐎅𐎘}} * {{Z|ur}}: {{W-|ur|شرم|tr=śarm}} * {{Z|uk}}: {{W-|uk|со́ром|n}}, {{W+|uk|ганьба́|m}}, {{W-|uk|стид|n}} * {{Z|vec}}: {{W-|vec|vargogna|m}} * {{Z|vi}}: {{W-|vi|sự xấu hổ}}, {{W-|vi|sự thẹn}}, {{W-|vi|sự ngượng}}, {{W-|vi|sự hổ thẹn}} * {{Z|cy}}: {{W-|cy|cywillydd|n}} * {{Z|km}}: {{W+|km|ខ្មាស|tr=kmaah|sc=Khmr}}, {{W+|km|អាស្រូវ|tr=aasrəv|sc=Khmr}}, {{W+|km|ហិរិ|tr=he’ri’|sc=Khmr}}, {{W-|km|លជ្ជាភាព|tr=lacciepʰiep|sc=Khmr}} * {{Z|yai}}: {{W-|yai|шарм}} * {{Z|ii}}: {{W-|ii|ꎲ}} * {{Z|el}}: {{W+|el|ντροπή|m}} *: Kevn: {{W-|grc|αἰσχύνη|m}} {{werger-bin}} :{{werger çavkanî|en|shame|beş=Ev qismê Wergerê|oldid=75746526}} == {{ziman|gmw-ecg}} == === Cînav === {{cînav|gmw-ecg}} # [[ew#ku|ew]] == {{ziman|sq}} == === Bilêvkirin === * {{deng|sq|LL-Q8748 (sqi)-Arianit-ar.wav|Deng|dever=Gjakova, Kosova}} === Navdêr === {{navdêr|sq}} # [[zêrr]] == {{ziman|eu}} == === Bilêvkirin === * {{deng|eu|LL-Q8752 (eus)-Xabier Cañas-ar.wav|Deng|dever=Donostia-San Sebastián, Spanya}} === Navdêr === {{navdêr|eu}} # [[nêr]] == {{ziman|da}} == === Navdêr === {{navdêr|da}} # [[bizmate]], [[şûn]], [[şop]] == {{ziman|ang}} == === Navdêr === {{navdêr|ang}} # [[navdarî]], [[meşhûrî]], [[navûdeng]], [[şan]], [[şeref]] == {{ziman|gl}} == === Navdêr === {{navdêr|gl|z=n}} # {{mijar|gl|hewa}} {{g|ku|hewa}} === Çavkanî === {{rûpela wergerê|gl|hewa}} == {{ziman|ga}} == === Bilêvkirin === * {{deng|ga|LL-Q9142 (gle)-Ériugena-ar.wav|Deng|dever=Îrland, QY}} === Daçek === {{daçek|ga}} # [[li ser]], [[li]] == {{ziman|lv}} == === Daçek === {{daçek|lv}} # [[li gel]], [[pê re]], [[bi ... re]] == {{ziman|pox}} == === Girêdek === {{girêdek|pox}} # [[yan#ku|yan]], [[an#ku|an]] == {{ziman|pt}} == === Bilêvkirin === * {{deng|pt|LL-Q5146 (por)-Santamarcanda-ar.wav|Deng|dever=Porto, Portûgal}} * {{deng|pt|LL-Q5146 (por)-Nelson Ricardo 2500-ar.wav|Deng|dever=DYA}} === Navdêr === {{navdêr|pt|z=n}} # [[hewa]] == {{ziman|sv}} == === Navdêr === {{navdêr|sv}} # [[ar#Kurdî|ar]] (100 m<sup>2</sup>) == {{ziman|tr}} == === Bilêvkirin === * {{deng|tr|LL-Q256 (tur)-ToprakM-ar.wav|Deng|dever=Îzmîr, Tirkiye}} === Navdêr === {{navdêr|tr}} # [[ar#Kurdî|ar]] (100 m<sup>2</sup>) == {{ziman|zza}} == === Navdêr === {{navdêr|zza|z=}} # [[afir]], ciyê ku têda alef didin heywanên gird<ref>http://www.kovarabir.com/wp-content/uploads/Ferheng%C3%AA-Dimil%C3%AE-Zazak%C3%AE-%C3%BB-Kurmanc%C3%AE-A-a.pdf</ref> === Çavkanî === {{çavkanî}} == {{ziman|cy}} == === Daçek === {{daçek|cy}} # {{g|ku|li ser}} === Çavkanî === {{rûpela wergerê|cy|li ser}} tlt0k0tciehahtl3rpw6j75tic09m4v bajar 0 3423 6291737 6261982 2026-07-27T23:00:46Z Ghybu 1393 alt 6291737 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/bɑ:ˈʒɑ:r/}}, {{ku-Arab|باژاڕ}} * {{ku-kîte}} * {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-bajar.wav|Deng|Bidlîs}} === Navdêr === {{ku-tewîn-nav|bajar|nêr|alt.çemandî.yj=baj'''ê'''r}} [[Wêne:Hawler Castle.jpg|thumb|250px|'''Bajarê''' Hewlêrê.]] {{navdêr|ku|z=n}}, {{bilêv|r|req}} # [[cih|Cihê]] ku gelek [[avahî]] û [[kuçe]] lê hene û gelek xelk lê di[[jîn]] û [[xebitîn|dixebitin]]. #: {{hevmaneyên peyvê|ku|şehr|sûk|medîne}} #: {{mk|ku|Amed '''bajarekî''' kevnar e.}} #: {{mk|ku|Dihok wek turîstîktirîn '''bajarê''' Başûrê Kurdistanê tê hesibandin.}} #* {{jêder-pirtûk|ku|jêgirtin=Barîna berfê şênayiyek bû. Kuçe û kolanên '''bajêr''' ji zarokan tijî dibûn.|sernav=Tu|nivîskar={{w|Mehmed Uzun}}|sal=1984}} # [[navend|Navenda]] bajarî, cihê [[firoşgeh]]an. #: {{hevmaneyên peyvê|ku|sûk|bazar}} #: {{mk|ku|Ez li taxekê dijîm lê li '''bajarî''' kar dikim.}} # [[cih|Cih]] [[kirîn]] [[û]] [[firotin]]ê, cihê [[firoşgeh]]an. #: {{mk|ku|Ez ê biçim '''bajarî''' / '''bajêr'''.}} ==== Bi alfabeyên din ==== * {{ku-ar|باژاڕ}} * {{ku-kr|бажарʹ}} ==== Formên alternatîv ==== {{kol3|ku| | {{hw|ku|bajarr}} | {{hw|ku|bacar}}, {{hw|ku|bacarr}} | {{hw|ku|bacêr}}, {{hw|ku|bacêrr}} | {{hw|ku|bajêr}}, {{hw|ku|bajêrr}} }} ==== Jê ==== {{kol3|ku | bajarî | bajarîtî | bajarok | bajarokî | bajarvan | bajarvanî | serbajar | serbajarî }} ==== Têkilî ==== {{kol3|ku | dewlet | eyalet | gund | metropol | navçe | nahiye | qeza | parêzgeh | welat | wîlayet }} ==== Etîmolojî ==== Hevreha {{hv|fa|بازار|tr=bazar}}, pehlewî {{g|pal|𐭥𐭠𐭰𐭠𐭫|tr=wazar}}, hexamenişî {{g|peo|𐎺𐏃𐎠𐎨𐎼𐎴|tr=vehā-čā̆rana-}} ji {{ji|ira-pro|ku|*wahā-čā̆rana-|w=[[bazarkirin]], [[firotin]], [[danûstandin]], [[hatinûçûn]]}} ji {{ji|ine-pro|ku|*wes-|w=[[firotin]], [[nirx]], [[biha]], [[qîmet]]}} + {{g|ine-pro|*kʷel-|w=[[livandin]], [[çerixandin]], [[wergerandin]]}}. [[hevreh|Hevreha]] {{q|ku|biha}} ya kurmancî, {{q|zza|vaya}} ya zazakî, ''vasná-'' ("[[biha]], [[nirx]]") ya sanskrîtî, ''gin'' ("[[biha]], [[nirx]]") ya ermenî, {{q|la|vēndere|w=[[firotin]]}} ya latînî > {{q|fr|vendre}} ya fransî. Peyva ''bajar'' kurmancî û ya ''bazar'' jî farisî ye lê kurdî peyva ''bazar'' bo mebestek hinekî ji ya bajar cuda ji farisî deyn kiriye. Hêjayî gotinê ye ku ji bilî kurmancî, di zaravayên din yên kurdî de gotina ''bajar'' kêm tê bikaranîn. Ji bo cihê kirîn û firotinê bi giştî {{cotreh|ku|bazar|nivîs=na}} ya ji farisî û bi merema ''jîngehên mezin'' jî gotina {{q|ckb|şar|sc=Latn}} (di soranî de) yan jî {{q|zza|şaristan}} (di zazakî de) li kar e. Ev peyv bi maneya "bazar, sûk, çarsû" ji zimanên îranî ketiye gelek zimanên din jî: ermenî {{g|hy|բազար|tr=bazar}} û {{g|hy|վաճառ|tr=vačaṙ}}, gurcî {{g|ka|ვაჭარი|tr=vač̣ari}}, erebî {{g|ar|بازار‎|tr=bazar}}, osmanî {{g|ota|بازار‎|tr=bazar}} û {{g|ota|پازار‎|tr=pazar}}, tirkî {{g|tr|pazar}}, azerî {{g|az|bazar}} / {{g|az|базар|sc=Cyrl}}, ûrdûyî {{g|ur|بازار‎|tr=bazar}}, hindî {{g|hi|बाज़ार|tr=bazar}}, bengalî {{g|bn|বাজার|tr=bajar}}, nepalî {{g|ne|बजार|tr=bajar}}, endonezyayî {{g|id|pasar}}, çînî {{g|zh|巴扎|tr=bāzhā}} û {{g|zh|巴刹|tr=pa-sat}}, rusî {{g|ru|база́р|tr=bazár}}, yûnanî {{g|el|παζάρι|tr=pazári}}, mecarî/hungarî [[vásár]], sirbokroatî [[ва́шар]] / [[vašar]], fransî/îtalî/{{hv|es|bazar}}, {{hv|en|bazaar}}, {{hv|de|Basar}}, danmarkî/norwecî/{{hv|sv|basar}}, fînlandî ''[[basaari]]''... ==== Bi zaravayên din ==== * {{Z|ckb}}: {{W-|ckb|شار|tr=[[şar]]}}, {{W-|ckb|باژار|tr=bajar}}, {{W-|ckb|bajêr|sc=Latn}} * {{Z|zza}}: [[bacar|bajar]], [[sûke]], [[şaristan]], [[şehr]] ==== Anagram ==== * {{anagram|ku|a=aabjr|baraj}} ==== Werger ==== {{werger-ser}} * {{Z|ab}}: {{W-|ab|ақалақь}} * {{Z|af}}: {{W+|af|stad}} * {{Z|akk}}: {{W-|akk|𒌷|tr=âlu}} * {{Z|sq}}: {{W+|sq|qytet}} * {{Z|gmw-ecg}}: {{W-|gmw-ecg|Stoadt}} * {{Z|pdc}}: {{W-|pdc|Schtadt}}, {{W-|pdc|Schtedt}} * {{Z|de}}: {{W+|de|Stadt|m}}, {{W+|de|Großstadt|m}} * {{Z|alt}}: {{W-|alt|кала}} * {{Z|abs}}: {{W-|abs|kota}} * {{Z|am}}: {{W+|am|ከተማ}} * {{Z|an}}: {{W-|an|ziudá|m}} * {{Z|arc}}: *: Îbranî: {{W-|arc|מְדִינְתָּא|m|tr=məḏīntā}}, {{W-|arc|כַּרְכָּא|n|tr=karkā}} *: Siryanî: {{W-|arc|ܡܕܼܝܼܢܬܿܵܐ|m|tr=məḏīttā}}, {{W-|arc|ܟܿܲܪܟܿܵܐ|n|tr=karkā}} * {{Z|agj}}: {{W-|agj|ኸተም|tr=xatame}} * {{Z|rup}}: {{W+|rup|cãsãbã|m}} * {{Z|as}}: {{W-|as|নগৰ}}, {{W-|as|চহৰ}} * {{Z|ast}}: {{W+|ast|ciudá|m}} * {{Z|av}}: {{W-|av|шагьар}} * {{Z|az}}: {{W+|az|şəhər}} * {{Z|eu}}: {{W+|eu|hiri}} * {{Z|ba}}: {{W-|ba|ҡала}} * {{Z|be}}: {{W-|be|го́рад|n}}, {{W-|be|ме́ста|nt}} * {{Z|bn}}: {{W+|bn|শহর}}, {{W+|bn|নগর}} * {{Z|br}}: {{W-|br|keoded|m}}, {{W-|br|keodedoù|p}}, {{W+|br|kêr|m}}, {{W+|br|kêrioù|p}} * {{Z|bg}}: {{W+|bg|град|n}} * {{Z|my}}: {{W+|my|မြို့}} * {{Z|bua}}: {{W-|bua|хото}} * {{Z|ccc}}: {{W-|ccc|chi'nashtalichi}} * {{Z|ce}}: {{W-|ce|гӏала}} * {{Z|cs}}: {{W+|cs|město|nt}}, {{W+|cs|velkoměsto|nt}} * {{Z|ny}}: {{W-|ny|mzinda}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|城市}} *: {{Z|dng}}: {{W-|dng|чыншы}}, {{W-|dng|чын}}, {{W-|dng|шы}}, {{W-|dng|чынпу}} *: {{Z|hak}}: {{W-|hak|城市|tr=sàng-sṳ}} *: {{Z|cmn}}: {{W+|cmn|城市}}, {{W+|cmn|都市}}, {{W+|cmn|城|tr=chéng}}, {{W+|cmn|市|tr=shì}} *: {{Z|cdo}}: {{W-|cdo|城市}} *: {{Z|nan}}: {{W+|nan|城市|tr=siâⁿ-chhī / siâⁿ-chhǐ}}, {{W+|nan|都市|tr=to·-chhī}} *: {{Z|wuu}}: {{W-|wuu|城市}} * {{Z|cv}}: {{W-|cv|хула}} * {{Z|dlm}}: {{W-|dlm|cituot|m}} * {{Z|da}}: {{W+|da|by|g}} * {{Z|dv}}: {{W-|dv|ޝަހަރު}} * {{Z|sce}}: {{W-|sce|baza}} * {{Z|id}}: {{W+|id|kota}} * {{Z|ar}}: {{W+|ar|مَدِينَة|m}}, {{W+|ar|بَلَد|n}} *: {{Z|arz}}: {{W-|arz|بَلَد|tr=balad}} *: {{Z|afb}}: {{W-|afb|مَدينَة|m|tr=mədina}} *: {{Z|ary}}: {{W-|ary|مدِينَة|tr=mdīna}} * {{Z|hy}}: {{W+|hy|քաղաք}} * {{Z|myv}}: {{W-|myv|ош}} * {{Z|eo}}: {{W+|eo|urbo}}, {{W+|eo|civito}} * {{Z|et}}: {{W+|et|linn}} * {{Z|gez}}: {{W-|gez|ሀገር|m}} * Georgian: {{l|ka|დიდი}} {{W+|ka|ქალაქი}} * {{Z|ext}}: {{W-|ext|ciá|m}} * {{Z|fa}}: {{W+|fa|شَهر|tr=šahr}} * {{Z|phn}}: {{W-|phn|𐤀𐤄𐤋}} * {{Z|fo}}: {{W+|fo|býur|n}} * {{Z|fi}}: {{W+|fi|kaupunki}} * {{Z|fr}}: {{W+|fr|ville|m}}, {{W+|fr|cité|m}}, {{W-|fr|grande-ville|m}} *: {{Z|fro}}: {{W-|fro|cité|m}} * {{Z|fur}}: {{W-|fur|citât|m}} * {{Z|frr}}: {{W-|frr|steed|nt}} * {{Z|stq}}: {{W-|stq|Stääd|m}} * {{Z|fy}}: {{W+|fy|stêd|g}} * {{Z|gd}}: {{W-|gd|baile mòr|n}}, {{W-|gd|dùn|n}} * {{Z|gl}}: {{W+|gl|cidade|m}} * {{Z|sdn}}: {{W-|sdn|cittai|m}}, {{W-|sdn|zittai|m}} * {{Z|got}}: {{W-|got|𐌱𐌰𐌿𐍂𐌲𐍃|m|tr=baurgs}} * {{Z|gu}}: {{W+|gu|શહેર}}, {{W+|gu|નગર}} * {{Z|gn}}: {{W+|gn|táva}} * {{Z|ht}}: {{W-|ht|vil}} * {{Z|haw}}: {{W-|haw|kūlanakauhale}} * {{Z|ha}}: {{W+|ha|birni}} * {{Z|hi}}: {{W+|hi|शहर|n}}, {{W+|hi|नगर|n}} * {{Z|hil}}: {{W-|hil|dakbanwa}} * {{Z|nl}}: {{W+|nl|stad|m}} * {{Z|hrx}}: {{W-|hrx|xtat}} * {{Z|he}}: {{W+|he|עִיר|m|tr=ir}} * {{Z|io}}: {{W+|io|urbo}}, {{W+|io|civito}} * {{Z|ang}}: {{W-|ang|burg|m}} * {{Z|enm}}: {{W-|enm|cite}} * {{Z|en}}: {{W+|en|city}}, {{W+|en|town}} * {{Z|ia}}: {{W-|ia|citate}} * {{Z|ga}}: {{W+|ga|cathair|m}}, {{W-|ga|baile mór|n}} * {{Z|ist}}: {{W-|ist|sità|m}} * {{Z|it}}: {{W+|it|città|m}} * {{Z|is}}: {{W+|is|borg|m}} * {{Z|ja}}: {{W+|ja|都市|tr=とし, toshi}}, {{W+|ja|都会|tr=とかい, tokai}}, {{W+|ja|町|tr=まち, machi}} (e.g. 町で - "in the city"), {{W+|ja|市|tr=し, shi}} * {{Z|jv}}: {{W-|jv|kutha}} * {{Z|kbd}}: {{W-|kbd|къалэ}} * {{Z|xal}}: {{W-|xal|балһсн}} * {{Z|kn}}: {{W+|kn|ನಗರ}} * {{Z|pam}}: {{W-|pam|lakanbalen}} * {{Z|krc}}: {{W-|krc|шахар|tr=şaxar}} * {{Z|krl}}: {{W-|krl|linna}} * {{Z|csb}}: {{W-|csb|miasto|nt}} * {{Z|ca}}: {{W+|ca|ciutat|m}} * {{Z|qu}}: {{W+|qu|llaqta}} * {{Z|ky}}: {{W+|ky|шаар}}, {{W+|ky|калаа}} * {{Z|si}}: {{W+|si|නගරය}} * {{Z|koi}}: {{W-|koi|кар}} * {{Z|kpv}}: {{W-|kpv|кар}} * {{Z|kok}}: {{W-|kok|xar}} * {{Z|ko}}: {{W-|ko|도시(都市)}}, {{W-|ko|시내(市內)}}, {{W-|ko|시(市)}} * {{Z|kw}}: {{W-|kw|cita}} * {{Z|co}}: {{W-|co|cità}} * {{Z|kum}}: {{W-|kum|шагьар|tr=şahar}} * {{Z|kgg}}: {{W-|kgg|səhər}} * {{Z|lld}}: {{W-|lld|zità|m}} * {{Z|la}}: {{W+|la|urbs|m}}, {{W+|la|civitas|m}} * {{Z|lv}}: {{W+|lv|pilsēta|m}} (or {{W-|lv|lielpilsēta|m}} if the distinction between ''city'' and ''town'' is important) * {{Z|lo}}: {{W-|lo|ຊຽງ}}, {{W-|lo|ທານີ}}, {{W+|lo|ເມືອງ}}, {{W-|lo|ນະຄອນ}} * {{Z|roa-leo}}: {{W-|roa-leo|ciudá|m}} * {{Z|lij}}: {{W-|lij|çitæ}}, {{W-|lij|çittæ}} * {{Z|lt}}: {{W+|lt|miestas|n}} * {{Z|khb}}: {{W-|khb|ᦵᦙᦲᧂ}}, {{W-|khb|ᨾᩮᩥ᩠ᨦ}}, {{W-|khb|ᦵᦞᦇ}}, {{W-|khb|ᦵᦋᧂ}} * {{Z|lb}}: {{W+|lb|Stad}} * {{Z|mk}}: {{W-|mk|град|n}} * {{Z|mg}}: {{W+|mg|monina}}, {{W+|mg|tanambe}} * {{Z|ml}}: {{W+|ml|നഗരം}} * {{Z|ms}}: {{W+|ms|bandar raya}}, {{W+|ms|kota}}, {{W+|ms|bandar}} * {{Z|mt}}: {{W+|mt|belt|m}} * {{Z|mnc}}: {{W-|mnc|ᡥᠣᡨᠣᠨ}}, {{W-|mnc|ᡥᡝᠴᡝᠨ}} * {{Z|gv}}: {{W-|gv|ard-valley|n}}, {{W-|gv|caayr|m}} * {{Z|mi}}: {{W+|mi|tāone}}, {{W-|mi|tāone nui}} * {{Z|mr}}: {{W+|mr|शहर}}, {{W-|mr|नगर}} * {{Z|mhr}}: {{W-|mhr|ола}} * {{Z|mrc}}: {{W-|mrc|vakpaly}} * {{Z|hu}}: {{W+|hu|város}} * {{Z|gdq}}: {{W-|gdq|رحبيت}} * {{Z|egy}}: {{W-egy|nwt|h=niwt:t*Z1|m}} * {{Z|mdf}}: {{W-|mdf|ош}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|хот}} *: Mongolî: {{W-|mn|ᠬᠣᠲᠠ}} * {{Z|nah}}: {{W+|nah|altepetl}} * {{Z|nv}}: {{W-|nv|kin nitsaago dah naazhjaaʼígíí}}, {{W-|nv|kin haalʼá}} * {{Z|ne}}: {{W+|ne|सहर}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|by|n}} *: {{Z|nn}}: {{W-|nn|by|n}} * Nubian: *: {{Z|fia}}: {{W-|fia|diffi}} (ⲇⲓⲫⲫⲓ, ديفي) *: {{Z|onw}}: {{W-|onw|ⲇⲡ̅ⲡ}} * {{Z|oj}}: {{W-|oj|gichi-oodena}} * {{Z|oc}}: {{W+|oc|ciutat|m}} * {{Z|or}}: {{W+|or|ନଗର}}, {{W-|or|ମହାନଗର}} * {{Z|om}}: {{W-|om|magaalaa}} * {{Z|os}}: {{W-|os|сахар}}, {{W-|os|горӕт}} * {{Z|ug}}: {{W-|ug|شەھەر}} * {{Z|uz}}: {{W+|uz|shahar}} * {{Z|pgn}}: {{W-|pgn|banudara}} * {{Z|pi}}: {{W-|pi|nagara|nt}} * {{Z|pap}}: {{W-|pap|siudat}} * {{Z|bxd}}: {{W-|bxd|mjuʔ⁵⁵}} * {{Z|ps}}: {{W+|ps|ښار|n|tr=ẍâr}} * {{Z|pms}}: {{W-|pms|sità|m}} * {{Z|pdt}}: {{W-|pdt|Grootstaut|m}}, {{W-|pdt|Staut|m}} * {{Z|pl}}: {{W+|pl|miasto|nt}} * {{Z|roa-opt}}: {{W-|roa-opt|cidade|m}} * {{Z|pt}}: {{W+|pt|cidade|m}}, {{W+|pt|urbe|m}} * Puncabî: *: Şaxmuxî: {{W+|pa|شہر}}, {{W+|pa|نگر}} *: Gurmuxî: {{W+|pa|ਸ਼ਹਿਰ}} * {{Z|kk}}: {{W+|kk|қала}}, {{W-|kk|шаһар}} * {{Z|cop}}: {{W-|cop|ⲃⲁⲕⲓ}} * {{Z|rgn}}: {{W-|rgn|zitê|m}} * {{Z|rm}}: {{W-|rm|citad|m}} * {{Z|ro}}: {{W+|ro|oraș|nt}}, {{W+|ro|cetate|m}}, {{W+|ro|urbe|m}} * {{Z|ru}}: {{W+|ru|го́род|n}}, {{W+|ru|град|n}} * {{Z|rue}}: {{W-|rue|мі́сто|nt}} * {{Z|sms}}: {{W-|sms|gåårad}}, {{W-|sms|lâ´nn}} * {{Z|sa}}: {{W+|sa|नगर|nt}} * {{Z|sdc}}: {{W-|sdc|ziddai|m}} * {{Z|ceb}}: {{W-|ceb|dakbayan}}, {{W-|ceb|siyudad}} * {{Z|scn}}: {{W+|scn|cità|m}}, {{W+|scn|citati}} * {{Z|szl}}: {{W-|szl|miasto|nt}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|гра̑д|n}} *: Latînî: {{W+|sh|grȃd|n}} * {{Z|syl}}: {{W-|syl|ꠘꠉꠞ}} * {{Z|sco}}: {{W-|sco|ceity}}, {{W-|sco|ceety}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|градъ|n}}, {{W-|cu|мѣсто|nt}} * {{Z|orv}}: {{W-|orv|градъ|n}}, {{W-|orv|мѣсто|nt}}, {{W-|orv|городъ|n}} * {{Z|sk}}: {{W+|sk|mesto|nt}} * {{Z|sl}}: {{W+|sl|mésto|nt}} * {{Z|so}}: {{W+|so|magaalo}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|město|nt}} *: {{Z|hsb}}: {{W+|hsb|město|nt}} * {{Z|es}}: {{W+|es|ciudad|m}}, {{W+|es|urbe|m}} * {{Z|sux}}: {{W-|sux|𒌷|tr=URU}} * {{Z|sw}}: {{W+|sw|mji}} * {{Z|sv}}: {{W+|sv|stad|g}} * {{Z|cjs}}: {{W-|cjs|тура|tr=tura}} * {{Z|tg}}: {{W+|tg|шаҳр}} * {{Z|tl}}: {{W+|tl|lungsod}}, {{W-|tl|syudad}} * {{Z|ta}}: {{W+|ta|நகரம்}} * {{Z|twf}}: {{W-|twf|plòso’óna}} * {{Z|rif}}: {{W-|rif|ṯendint}}, {{W-|rif|tamdint|m}} * {{Z|tsg}}: {{W-|tsg|daira}} * {{Z|th}}: {{W+|th|เมือง}}, {{W+|th|นคร}}, {{W+|th|กรุง}}, {{W+|th|เชียง}} * {{Z|te}}: {{W+|te|నగరం}} * {{Z|crh}}: {{W-|crh|şeer}} * {{Z|tt}}: {{W+|tt|шәһәр}}, {{W+|tt|кала}} * {{Z|tet}}: {{W-|tet|sidade}} * {{Z|ti}}: {{W-|ti|ከተማ}} * {{Z|tr}}: {{W+|tr|kent}}, {{W+|tr|şehir}} * {{Z|tk}}: {{W-|tk|şäher}} * {{Z|bo}}: {{W-|bo|གྲོང་ཁྱེར}}, {{W-|bo|རྒྱལ་ས}} * {{Z|txb}}: {{W-|txb|rīye}} * {{Z|tyv}}: {{W-|tyv|хоорай}} * {{Z|udm}}: {{W-|udm|кар}} * {{Z|uga}}: {{W-|uga|𐎓𐎗}} * {{Z|ur}}: {{W-|ur|شَہَر|n|tr=śahar}}, {{W-|ur|نَگَر|n|tr=nagar}} * {{Z|uk}}: {{W+|uk|мі́сто|nt}}, {{W+|uk|град|n}} * {{Z|vec}}: {{W+|vec|sità|m}}, {{W-|vec|çità|m}} * {{Z|vi}}: {{W+|vi|thành phố}} ({{W-|vi|城埔}}), {{W+|vi|thành}}, {{W+|vi|phố}}, {{W+|vi|đô thị}} ({{W-|vi|都市}}) * {{Z|vo}}: {{W+|vo|zif}} * {{Z|vro}}: {{W-|vro|liin}} * {{Z|wa}}: {{W+|wa|veye}} * {{Z|cy}}: {{W+|cy|caer|m}}, {{W+|cy|dinas|m}} * {{Z|wo}}: {{W+|wo|dëkk}} * {{Z|kjh}}: {{W-|kjh|саар}}, {{W-|kjh|город}} * {{Z|km}}: {{W-|km|ទីក្រុង}}, {{W+|km|បុរី}}, {{W+|km|នគរ}} * {{Z|xh}}: {{W-|xh|idolophu}} * {{Z|yai}}: {{W-|yai|шаҳр}} * {{Z|sah}}: {{W-|sah|куорат}} * {{Z|yi}}: {{W-|yi|שטאָט|m}} * {{Z|ii}}: {{W-|ii|ꇓꈓ}} * {{Z|yo}}: {{W-|yo|ìlú}} * {{Z|esu}}: {{W-|esu|nunarpak}} * {{Z|pnt}}: {{W-|pnt|πολιτεία|m}} * {{Z|el}}: {{W+|el|πόλη|m}} *: Kevn: {{W-|grc|πόλις|m}}, {{W-|grc|ἄστυ|nt}} * {{Z|za}}: {{W-|za|si}}, {{W-|za|hawsingz}}, {{W-|za|singz}} * {{Z|zu}}: {{W-|zu|ithawini}} {{werger-bin}} 30v7xu00tbabd5jpgeay1vsvyv285qo 6291738 6291737 2026-07-27T23:06:33Z Ghybu 1393 /* Navdêr */kurtenav 6291738 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/bɑ:ˈʒɑ:r/}}, {{ku-Arab|باژاڕ}} * {{ku-kîte}} * {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-bajar.wav|Deng|Bidlîs}} === Navdêr === {{ku-tewîn-nav|bajar|nêr|alt.çem.yj=baj'''ê'''r}} [[Wêne:Hawler Castle.jpg|thumb|250px|'''Bajarê''' Hewlêrê.]] {{navdêr|ku|z=n}}, {{bilêv|r|req}} # [[cih|Cihê]] ku gelek [[avahî]] û [[kuçe]] lê hene û gelek xelk lê di[[jîn]] û [[xebitîn|dixebitin]]. #: {{hevmaneyên peyvê|ku|şehr|sûk|medîne}} #: {{mk|ku|Amed '''bajarekî''' kevnar e.}} #: {{mk|ku|Dihok wek turîstîktirîn '''bajarê''' Başûrê Kurdistanê tê hesibandin.}} #* {{jêder-pirtûk|ku|jêgirtin=Barîna berfê şênayiyek bû. Kuçe û kolanên '''bajêr''' ji zarokan tijî dibûn.|sernav=Tu|nivîskar={{w|Mehmed Uzun}}|sal=1984}} # [[navend|Navenda]] bajarî, cihê [[firoşgeh]]an. #: {{hevmaneyên peyvê|ku|sûk|bazar}} #: {{mk|ku|Ez li taxekê dijîm lê li '''bajarî''' kar dikim.}} # [[cih|Cih]] [[kirîn]] [[û]] [[firotin]]ê, cihê [[firoşgeh]]an. #: {{mk|ku|Ez ê biçim '''bajarî''' / '''bajêr'''.}} ==== Bi alfabeyên din ==== * {{ku-ar|باژاڕ}} * {{ku-kr|бажарʹ}} ==== Formên alternatîv ==== {{kol3|ku| | {{hw|ku|bajarr}} | {{hw|ku|bacar}}, {{hw|ku|bacarr}} | {{hw|ku|bacêr}}, {{hw|ku|bacêrr}} | {{hw|ku|bajêr}}, {{hw|ku|bajêrr}} }} ==== Jê ==== {{kol3|ku | bajarî | bajarîtî | bajarok | bajarokî | bajarvan | bajarvanî | serbajar | serbajarî }} ==== Têkilî ==== {{kol3|ku | dewlet | eyalet | gund | metropol | navçe | nahiye | qeza | parêzgeh | welat | wîlayet }} ==== Etîmolojî ==== Hevreha {{hv|fa|بازار|tr=bazar}}, pehlewî {{g|pal|𐭥𐭠𐭰𐭠𐭫|tr=wazar}}, hexamenişî {{g|peo|𐎺𐏃𐎠𐎨𐎼𐎴|tr=vehā-čā̆rana-}} ji {{ji|ira-pro|ku|*wahā-čā̆rana-|w=[[bazarkirin]], [[firotin]], [[danûstandin]], [[hatinûçûn]]}} ji {{ji|ine-pro|ku|*wes-|w=[[firotin]], [[nirx]], [[biha]], [[qîmet]]}} + {{g|ine-pro|*kʷel-|w=[[livandin]], [[çerixandin]], [[wergerandin]]}}. [[hevreh|Hevreha]] {{q|ku|biha}} ya kurmancî, {{q|zza|vaya}} ya zazakî, ''vasná-'' ("[[biha]], [[nirx]]") ya sanskrîtî, ''gin'' ("[[biha]], [[nirx]]") ya ermenî, {{q|la|vēndere|w=[[firotin]]}} ya latînî > {{q|fr|vendre}} ya fransî. Peyva ''bajar'' kurmancî û ya ''bazar'' jî farisî ye lê kurdî peyva ''bazar'' bo mebestek hinekî ji ya bajar cuda ji farisî deyn kiriye. Hêjayî gotinê ye ku ji bilî kurmancî, di zaravayên din yên kurdî de gotina ''bajar'' kêm tê bikaranîn. Ji bo cihê kirîn û firotinê bi giştî {{cotreh|ku|bazar|nivîs=na}} ya ji farisî û bi merema ''jîngehên mezin'' jî gotina {{q|ckb|şar|sc=Latn}} (di soranî de) yan jî {{q|zza|şaristan}} (di zazakî de) li kar e. Ev peyv bi maneya "bazar, sûk, çarsû" ji zimanên îranî ketiye gelek zimanên din jî: ermenî {{g|hy|բազար|tr=bazar}} û {{g|hy|վաճառ|tr=vačaṙ}}, gurcî {{g|ka|ვაჭარი|tr=vač̣ari}}, erebî {{g|ar|بازار‎|tr=bazar}}, osmanî {{g|ota|بازار‎|tr=bazar}} û {{g|ota|پازار‎|tr=pazar}}, tirkî {{g|tr|pazar}}, azerî {{g|az|bazar}} / {{g|az|базар|sc=Cyrl}}, ûrdûyî {{g|ur|بازار‎|tr=bazar}}, hindî {{g|hi|बाज़ार|tr=bazar}}, bengalî {{g|bn|বাজার|tr=bajar}}, nepalî {{g|ne|बजार|tr=bajar}}, endonezyayî {{g|id|pasar}}, çînî {{g|zh|巴扎|tr=bāzhā}} û {{g|zh|巴刹|tr=pa-sat}}, rusî {{g|ru|база́р|tr=bazár}}, yûnanî {{g|el|παζάρι|tr=pazári}}, mecarî/hungarî [[vásár]], sirbokroatî [[ва́шар]] / [[vašar]], fransî/îtalî/{{hv|es|bazar}}, {{hv|en|bazaar}}, {{hv|de|Basar}}, danmarkî/norwecî/{{hv|sv|basar}}, fînlandî ''[[basaari]]''... ==== Bi zaravayên din ==== * {{Z|ckb}}: {{W-|ckb|شار|tr=[[şar]]}}, {{W-|ckb|باژار|tr=bajar}}, {{W-|ckb|bajêr|sc=Latn}} * {{Z|zza}}: [[bacar|bajar]], [[sûke]], [[şaristan]], [[şehr]] ==== Anagram ==== * {{anagram|ku|a=aabjr|baraj}} ==== Werger ==== {{werger-ser}} * {{Z|ab}}: {{W-|ab|ақалақь}} * {{Z|af}}: {{W+|af|stad}} * {{Z|akk}}: {{W-|akk|𒌷|tr=âlu}} * {{Z|sq}}: {{W+|sq|qytet}} * {{Z|gmw-ecg}}: {{W-|gmw-ecg|Stoadt}} * {{Z|pdc}}: {{W-|pdc|Schtadt}}, {{W-|pdc|Schtedt}} * {{Z|de}}: {{W+|de|Stadt|m}}, {{W+|de|Großstadt|m}} * {{Z|alt}}: {{W-|alt|кала}} * {{Z|abs}}: {{W-|abs|kota}} * {{Z|am}}: {{W+|am|ከተማ}} * {{Z|an}}: {{W-|an|ziudá|m}} * {{Z|arc}}: *: Îbranî: {{W-|arc|מְדִינְתָּא|m|tr=məḏīntā}}, {{W-|arc|כַּרְכָּא|n|tr=karkā}} *: Siryanî: {{W-|arc|ܡܕܼܝܼܢܬܿܵܐ|m|tr=məḏīttā}}, {{W-|arc|ܟܿܲܪܟܿܵܐ|n|tr=karkā}} * {{Z|agj}}: {{W-|agj|ኸተም|tr=xatame}} * {{Z|rup}}: {{W+|rup|cãsãbã|m}} * {{Z|as}}: {{W-|as|নগৰ}}, {{W-|as|চহৰ}} * {{Z|ast}}: {{W+|ast|ciudá|m}} * {{Z|av}}: {{W-|av|шагьар}} * {{Z|az}}: {{W+|az|şəhər}} * {{Z|eu}}: {{W+|eu|hiri}} * {{Z|ba}}: {{W-|ba|ҡала}} * {{Z|be}}: {{W-|be|го́рад|n}}, {{W-|be|ме́ста|nt}} * {{Z|bn}}: {{W+|bn|শহর}}, {{W+|bn|নগর}} * {{Z|br}}: {{W-|br|keoded|m}}, {{W-|br|keodedoù|p}}, {{W+|br|kêr|m}}, {{W+|br|kêrioù|p}} * {{Z|bg}}: {{W+|bg|град|n}} * {{Z|my}}: {{W+|my|မြို့}} * {{Z|bua}}: {{W-|bua|хото}} * {{Z|ccc}}: {{W-|ccc|chi'nashtalichi}} * {{Z|ce}}: {{W-|ce|гӏала}} * {{Z|cs}}: {{W+|cs|město|nt}}, {{W+|cs|velkoměsto|nt}} * {{Z|ny}}: {{W-|ny|mzinda}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|城市}} *: {{Z|dng}}: {{W-|dng|чыншы}}, {{W-|dng|чын}}, {{W-|dng|шы}}, {{W-|dng|чынпу}} *: {{Z|hak}}: {{W-|hak|城市|tr=sàng-sṳ}} *: {{Z|cmn}}: {{W+|cmn|城市}}, {{W+|cmn|都市}}, {{W+|cmn|城|tr=chéng}}, {{W+|cmn|市|tr=shì}} *: {{Z|cdo}}: {{W-|cdo|城市}} *: {{Z|nan}}: {{W+|nan|城市|tr=siâⁿ-chhī / siâⁿ-chhǐ}}, {{W+|nan|都市|tr=to·-chhī}} *: {{Z|wuu}}: {{W-|wuu|城市}} * {{Z|cv}}: {{W-|cv|хула}} * {{Z|dlm}}: {{W-|dlm|cituot|m}} * {{Z|da}}: {{W+|da|by|g}} * {{Z|dv}}: {{W-|dv|ޝަހަރު}} * {{Z|sce}}: {{W-|sce|baza}} * {{Z|id}}: {{W+|id|kota}} * {{Z|ar}}: {{W+|ar|مَدِينَة|m}}, {{W+|ar|بَلَد|n}} *: {{Z|arz}}: {{W-|arz|بَلَد|tr=balad}} *: {{Z|afb}}: {{W-|afb|مَدينَة|m|tr=mədina}} *: {{Z|ary}}: {{W-|ary|مدِينَة|tr=mdīna}} * {{Z|hy}}: {{W+|hy|քաղաք}} * {{Z|myv}}: {{W-|myv|ош}} * {{Z|eo}}: {{W+|eo|urbo}}, {{W+|eo|civito}} * {{Z|et}}: {{W+|et|linn}} * {{Z|gez}}: {{W-|gez|ሀገር|m}} * Georgian: {{l|ka|დიდი}} {{W+|ka|ქალაქი}} * {{Z|ext}}: {{W-|ext|ciá|m}} * {{Z|fa}}: {{W+|fa|شَهر|tr=šahr}} * {{Z|phn}}: {{W-|phn|𐤀𐤄𐤋}} * {{Z|fo}}: {{W+|fo|býur|n}} * {{Z|fi}}: {{W+|fi|kaupunki}} * {{Z|fr}}: {{W+|fr|ville|m}}, {{W+|fr|cité|m}}, {{W-|fr|grande-ville|m}} *: {{Z|fro}}: {{W-|fro|cité|m}} * {{Z|fur}}: {{W-|fur|citât|m}} * {{Z|frr}}: {{W-|frr|steed|nt}} * {{Z|stq}}: {{W-|stq|Stääd|m}} * {{Z|fy}}: {{W+|fy|stêd|g}} * {{Z|gd}}: {{W-|gd|baile mòr|n}}, {{W-|gd|dùn|n}} * {{Z|gl}}: {{W+|gl|cidade|m}} * {{Z|sdn}}: {{W-|sdn|cittai|m}}, {{W-|sdn|zittai|m}} * {{Z|got}}: {{W-|got|𐌱𐌰𐌿𐍂𐌲𐍃|m|tr=baurgs}} * {{Z|gu}}: {{W+|gu|શહેર}}, {{W+|gu|નગર}} * {{Z|gn}}: {{W+|gn|táva}} * {{Z|ht}}: {{W-|ht|vil}} * {{Z|haw}}: {{W-|haw|kūlanakauhale}} * {{Z|ha}}: {{W+|ha|birni}} * {{Z|hi}}: {{W+|hi|शहर|n}}, {{W+|hi|नगर|n}} * {{Z|hil}}: {{W-|hil|dakbanwa}} * {{Z|nl}}: {{W+|nl|stad|m}} * {{Z|hrx}}: {{W-|hrx|xtat}} * {{Z|he}}: {{W+|he|עִיר|m|tr=ir}} * {{Z|io}}: {{W+|io|urbo}}, {{W+|io|civito}} * {{Z|ang}}: {{W-|ang|burg|m}} * {{Z|enm}}: {{W-|enm|cite}} * {{Z|en}}: {{W+|en|city}}, {{W+|en|town}} * {{Z|ia}}: {{W-|ia|citate}} * {{Z|ga}}: {{W+|ga|cathair|m}}, {{W-|ga|baile mór|n}} * {{Z|ist}}: {{W-|ist|sità|m}} * {{Z|it}}: {{W+|it|città|m}} * {{Z|is}}: {{W+|is|borg|m}} * {{Z|ja}}: {{W+|ja|都市|tr=とし, toshi}}, {{W+|ja|都会|tr=とかい, tokai}}, {{W+|ja|町|tr=まち, machi}} (e.g. 町で - "in the city"), {{W+|ja|市|tr=し, shi}} * {{Z|jv}}: {{W-|jv|kutha}} * {{Z|kbd}}: {{W-|kbd|къалэ}} * {{Z|xal}}: {{W-|xal|балһсн}} * {{Z|kn}}: {{W+|kn|ನಗರ}} * {{Z|pam}}: {{W-|pam|lakanbalen}} * {{Z|krc}}: {{W-|krc|шахар|tr=şaxar}} * {{Z|krl}}: {{W-|krl|linna}} * {{Z|csb}}: {{W-|csb|miasto|nt}} * {{Z|ca}}: {{W+|ca|ciutat|m}} * {{Z|qu}}: {{W+|qu|llaqta}} * {{Z|ky}}: {{W+|ky|шаар}}, {{W+|ky|калаа}} * {{Z|si}}: {{W+|si|නගරය}} * {{Z|koi}}: {{W-|koi|кар}} * {{Z|kpv}}: {{W-|kpv|кар}} * {{Z|kok}}: {{W-|kok|xar}} * {{Z|ko}}: {{W-|ko|도시(都市)}}, {{W-|ko|시내(市內)}}, {{W-|ko|시(市)}} * {{Z|kw}}: {{W-|kw|cita}} * {{Z|co}}: {{W-|co|cità}} * {{Z|kum}}: {{W-|kum|шагьар|tr=şahar}} * {{Z|kgg}}: {{W-|kgg|səhər}} * {{Z|lld}}: {{W-|lld|zità|m}} * {{Z|la}}: {{W+|la|urbs|m}}, {{W+|la|civitas|m}} * {{Z|lv}}: {{W+|lv|pilsēta|m}} (or {{W-|lv|lielpilsēta|m}} if the distinction between ''city'' and ''town'' is important) * {{Z|lo}}: {{W-|lo|ຊຽງ}}, {{W-|lo|ທານີ}}, {{W+|lo|ເມືອງ}}, {{W-|lo|ນະຄອນ}} * {{Z|roa-leo}}: {{W-|roa-leo|ciudá|m}} * {{Z|lij}}: {{W-|lij|çitæ}}, {{W-|lij|çittæ}} * {{Z|lt}}: {{W+|lt|miestas|n}} * {{Z|khb}}: {{W-|khb|ᦵᦙᦲᧂ}}, {{W-|khb|ᨾᩮᩥ᩠ᨦ}}, {{W-|khb|ᦵᦞᦇ}}, {{W-|khb|ᦵᦋᧂ}} * {{Z|lb}}: {{W+|lb|Stad}} * {{Z|mk}}: {{W-|mk|град|n}} * {{Z|mg}}: {{W+|mg|monina}}, {{W+|mg|tanambe}} * {{Z|ml}}: {{W+|ml|നഗരം}} * {{Z|ms}}: {{W+|ms|bandar raya}}, {{W+|ms|kota}}, {{W+|ms|bandar}} * {{Z|mt}}: {{W+|mt|belt|m}} * {{Z|mnc}}: {{W-|mnc|ᡥᠣᡨᠣᠨ}}, {{W-|mnc|ᡥᡝᠴᡝᠨ}} * {{Z|gv}}: {{W-|gv|ard-valley|n}}, {{W-|gv|caayr|m}} * {{Z|mi}}: {{W+|mi|tāone}}, {{W-|mi|tāone nui}} * {{Z|mr}}: {{W+|mr|शहर}}, {{W-|mr|नगर}} * {{Z|mhr}}: {{W-|mhr|ола}} * {{Z|mrc}}: {{W-|mrc|vakpaly}} * {{Z|hu}}: {{W+|hu|város}} * {{Z|gdq}}: {{W-|gdq|رحبيت}} * {{Z|egy}}: {{W-egy|nwt|h=niwt:t*Z1|m}} * {{Z|mdf}}: {{W-|mdf|ош}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|хот}} *: Mongolî: {{W-|mn|ᠬᠣᠲᠠ}} * {{Z|nah}}: {{W+|nah|altepetl}} * {{Z|nv}}: {{W-|nv|kin nitsaago dah naazhjaaʼígíí}}, {{W-|nv|kin haalʼá}} * {{Z|ne}}: {{W+|ne|सहर}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|by|n}} *: {{Z|nn}}: {{W-|nn|by|n}} * Nubian: *: {{Z|fia}}: {{W-|fia|diffi}} (ⲇⲓⲫⲫⲓ, ديفي) *: {{Z|onw}}: {{W-|onw|ⲇⲡ̅ⲡ}} * {{Z|oj}}: {{W-|oj|gichi-oodena}} * {{Z|oc}}: {{W+|oc|ciutat|m}} * {{Z|or}}: {{W+|or|ନଗର}}, {{W-|or|ମହାନଗର}} * {{Z|om}}: {{W-|om|magaalaa}} * {{Z|os}}: {{W-|os|сахар}}, {{W-|os|горӕт}} * {{Z|ug}}: {{W-|ug|شەھەر}} * {{Z|uz}}: {{W+|uz|shahar}} * {{Z|pgn}}: {{W-|pgn|banudara}} * {{Z|pi}}: {{W-|pi|nagara|nt}} * {{Z|pap}}: {{W-|pap|siudat}} * {{Z|bxd}}: {{W-|bxd|mjuʔ⁵⁵}} * {{Z|ps}}: {{W+|ps|ښار|n|tr=ẍâr}} * {{Z|pms}}: {{W-|pms|sità|m}} * {{Z|pdt}}: {{W-|pdt|Grootstaut|m}}, {{W-|pdt|Staut|m}} * {{Z|pl}}: {{W+|pl|miasto|nt}} * {{Z|roa-opt}}: {{W-|roa-opt|cidade|m}} * {{Z|pt}}: {{W+|pt|cidade|m}}, {{W+|pt|urbe|m}} * Puncabî: *: Şaxmuxî: {{W+|pa|شہر}}, {{W+|pa|نگر}} *: Gurmuxî: {{W+|pa|ਸ਼ਹਿਰ}} * {{Z|kk}}: {{W+|kk|қала}}, {{W-|kk|шаһар}} * {{Z|cop}}: {{W-|cop|ⲃⲁⲕⲓ}} * {{Z|rgn}}: {{W-|rgn|zitê|m}} * {{Z|rm}}: {{W-|rm|citad|m}} * {{Z|ro}}: {{W+|ro|oraș|nt}}, {{W+|ro|cetate|m}}, {{W+|ro|urbe|m}} * {{Z|ru}}: {{W+|ru|го́род|n}}, {{W+|ru|град|n}} * {{Z|rue}}: {{W-|rue|мі́сто|nt}} * {{Z|sms}}: {{W-|sms|gåårad}}, {{W-|sms|lâ´nn}} * {{Z|sa}}: {{W+|sa|नगर|nt}} * {{Z|sdc}}: {{W-|sdc|ziddai|m}} * {{Z|ceb}}: {{W-|ceb|dakbayan}}, {{W-|ceb|siyudad}} * {{Z|scn}}: {{W+|scn|cità|m}}, {{W+|scn|citati}} * {{Z|szl}}: {{W-|szl|miasto|nt}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|гра̑д|n}} *: Latînî: {{W+|sh|grȃd|n}} * {{Z|syl}}: {{W-|syl|ꠘꠉꠞ}} * {{Z|sco}}: {{W-|sco|ceity}}, {{W-|sco|ceety}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|градъ|n}}, {{W-|cu|мѣсто|nt}} * {{Z|orv}}: {{W-|orv|градъ|n}}, {{W-|orv|мѣсто|nt}}, {{W-|orv|городъ|n}} * {{Z|sk}}: {{W+|sk|mesto|nt}} * {{Z|sl}}: {{W+|sl|mésto|nt}} * {{Z|so}}: {{W+|so|magaalo}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|město|nt}} *: {{Z|hsb}}: {{W+|hsb|město|nt}} * {{Z|es}}: {{W+|es|ciudad|m}}, {{W+|es|urbe|m}} * {{Z|sux}}: {{W-|sux|𒌷|tr=URU}} * {{Z|sw}}: {{W+|sw|mji}} * {{Z|sv}}: {{W+|sv|stad|g}} * {{Z|cjs}}: {{W-|cjs|тура|tr=tura}} * {{Z|tg}}: {{W+|tg|шаҳр}} * {{Z|tl}}: {{W+|tl|lungsod}}, {{W-|tl|syudad}} * {{Z|ta}}: {{W+|ta|நகரம்}} * {{Z|twf}}: {{W-|twf|plòso’óna}} * {{Z|rif}}: {{W-|rif|ṯendint}}, {{W-|rif|tamdint|m}} * {{Z|tsg}}: {{W-|tsg|daira}} * {{Z|th}}: {{W+|th|เมือง}}, {{W+|th|นคร}}, {{W+|th|กรุง}}, {{W+|th|เชียง}} * {{Z|te}}: {{W+|te|నగరం}} * {{Z|crh}}: {{W-|crh|şeer}} * {{Z|tt}}: {{W+|tt|шәһәр}}, {{W+|tt|кала}} * {{Z|tet}}: {{W-|tet|sidade}} * {{Z|ti}}: {{W-|ti|ከተማ}} * {{Z|tr}}: {{W+|tr|kent}}, {{W+|tr|şehir}} * {{Z|tk}}: {{W-|tk|şäher}} * {{Z|bo}}: {{W-|bo|གྲོང་ཁྱེར}}, {{W-|bo|རྒྱལ་ས}} * {{Z|txb}}: {{W-|txb|rīye}} * {{Z|tyv}}: {{W-|tyv|хоорай}} * {{Z|udm}}: {{W-|udm|кар}} * {{Z|uga}}: {{W-|uga|𐎓𐎗}} * {{Z|ur}}: {{W-|ur|شَہَر|n|tr=śahar}}, {{W-|ur|نَگَر|n|tr=nagar}} * {{Z|uk}}: {{W+|uk|мі́сто|nt}}, {{W+|uk|град|n}} * {{Z|vec}}: {{W+|vec|sità|m}}, {{W-|vec|çità|m}} * {{Z|vi}}: {{W+|vi|thành phố}} ({{W-|vi|城埔}}), {{W+|vi|thành}}, {{W+|vi|phố}}, {{W+|vi|đô thị}} ({{W-|vi|都市}}) * {{Z|vo}}: {{W+|vo|zif}} * {{Z|vro}}: {{W-|vro|liin}} * {{Z|wa}}: {{W+|wa|veye}} * {{Z|cy}}: {{W+|cy|caer|m}}, {{W+|cy|dinas|m}} * {{Z|wo}}: {{W+|wo|dëkk}} * {{Z|kjh}}: {{W-|kjh|саар}}, {{W-|kjh|город}} * {{Z|km}}: {{W-|km|ទីក្រុង}}, {{W+|km|បុរី}}, {{W+|km|នគរ}} * {{Z|xh}}: {{W-|xh|idolophu}} * {{Z|yai}}: {{W-|yai|шаҳр}} * {{Z|sah}}: {{W-|sah|куорат}} * {{Z|yi}}: {{W-|yi|שטאָט|m}} * {{Z|ii}}: {{W-|ii|ꇓꈓ}} * {{Z|yo}}: {{W-|yo|ìlú}} * {{Z|esu}}: {{W-|esu|nunarpak}} * {{Z|pnt}}: {{W-|pnt|πολιτεία|m}} * {{Z|el}}: {{W+|el|πόλη|m}} *: Kevn: {{W-|grc|πόλις|m}}, {{W-|grc|ἄστυ|nt}} * {{Z|za}}: {{W-|za|si}}, {{W-|za|hawsingz}}, {{W-|za|singz}} * {{Z|zu}}: {{W-|zu|ithawini}} {{werger-bin}} alyqpwj1oru59sd37yeowowsthikjsr ziman 0 3456 6291754 6261906 2026-07-27T23:18:28Z Ghybu 1393 6291754 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA|z(')iman}} * {{deng|ku|Kmr-ziman.wav|Deng|dever=Qamişlo}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|ziman|nêr|alt.çem.yj=zim'''ê'''n}} {{wp|ziman (endam)}} [[Wêne:Tongue.agr.jpg|thumb|100px|ziman (1)]] {{navdêr|ku|z=n}} # [[organ]]ekî [[nerm]] e di [[dev]]î de, <br> [[beş]]ek ji [[leş]]ê mirov û heywanan yê di [[dev]]î de ku bo [[tam]]kirin, [[alîstin]], [[daûrandin]]ê û (ji aliyê mirovan ve) bo [[axiftin]]ê tê [[bikaranîn]] #: {{mk|ku|'''Zimanê''' wê ji xwê kul bûbû.}} #* {{bêmînak|ku}} # [[axiftin]]a [[milet]]ekî,<br> [[axiftin]]a [[kom]]ekê, [[milet]]ekî, [[herêm]]ekê yan [[welat]]ekî ya ku ji alî [[pergal]]a xwe ve yek e û ji alî [[hemû]] kesên pê [[axiftin|diaxivin]] ve tê [[fehm]]kirin #: '''''zimanê''' kurdî, '''zimanê''' îngilîzî, '''zimanê''' erebî.'' # [[pergal]]a [[danûstandin]]ê,<br> [[sîstem]]a hemî [[deng]]ên mirov bi kar tînin daku [[peyam]]ên xwe bi hev bidin famkirin #* {{bêmînak|ku}} # [[danûstandin]]a bê[[gotin]],<br> [[jest]] û [[mîmîk]]ên mirov bi hev re bi kar tînin daku pê [[peyam]]a xwe bigihînin hev #* {{bêmînak|ku}} # [[danûstandin]]a [[lawir]]an,<br> [[deng]]ên [[heywan]] bi kar tînin daku peyamên xwe bigihînin hev yan kesekî / tiştekî #* {{bêmînak|ku}} # [[biwêj]]ên taybet, <br>[[pergal]]a [[ragihandin]]ê ya hin aliyên [[taybet]] #: '''''zimanê''' wêjeyê, '''zimanê''' kompûteriyê, '''zimanê''' leşkeriyê, '''zimanê''' gundiyan.'' # [[şêwaz]]ên [[bikaranîn]]a [[peyv]]an #: '''''zimanê''' dîplomasiyê.'' # [[hinêr]]a [[axiftin]]ê,<br> [[karîn]]a anku [[şiyan]]a [[peyivîn]]ê #: ''Ew bêziman e.'' # [[şêwe]]yê [[axiftin]]ê #: ''[[zimanxweş]]; [[zimandirêj]]'' #* {{jêder|ku|jêgirtin=Sofî bi goriya '''zimanê''' te be. Ew '''zimanê''' hungivîn û xweşik...|''[[w:Çiyayê Agirî|Çiyayê Agirî]]'', [[w:Yaşar Kemal|Yaşar Kemal]], Weşanxana [[w:Çanda Kurdî|Çanda Kurdî]]}} # {{f|ku|devokî}} [[kilîl|Kilîl]], [[kilît]], [[mifte]], [[enextar]], [[amûr]]ê ku [[derî]] pê tê [[vekirin]] #* {{bêmînak|ku}} ==== Bi alfabeyên din ==== * {{ku-ar|زمان}} * {{ku-kr|зьман}} ==== Formên alternatîv ==== {{kol3|ku |ezman<q:1> |zman }} ==== Hevmane ==== * {{mj|axiftin an nivîsîn}} [[lîsan]], [[luxet]] ==== Çemandî ==== * (''[[kurmanciya rojhilatî]]'') [[zimanî]] * (''[[kurmanciya navendî]] û [[kurmanciya rojavayî|rojavayî]]'') [[zimên]] ==== Têkilî ==== {{kol3|ku |dev |didan |hefik |gewrî |lêv |pidû |qirik }} ==== Jê ==== {{kol3|ku|cure=Jê |zimangirtî<q:rengdêr> |bêziman |bêzimanî |bêzimanîtî |bêzimantî |biziman |bizimanî |bizimanîtî |bizimantî |zimandar |zimandarî |zimandarîtî |zimandartî |zimandêr |zimandêrî |zimandêrîtî |zimandêrtî |zimandirêj |zimandirêjî |zimanê dayikî |zimanê zikmakî |zimanî |zimannas |zimanasî |zimanvan |zimanvanî |zimanxweş |zimanxweşî |zimanzan |zimanzanî |zimanzêrrîn |zimanzêrrînî }} ==== Etîmolojî ==== Herwiha ''[[ezman]]'', {{etymon|ku|id=organê xeberdanê|inh|ira-pro>*hižwáH>ziman|tree=1|text=++}} Hevreha {{hv|ckb|زمان|tr=ziman}}, {{hv|sdh|ziwan,zwan|sc=Latn}}, {{hv|hac|ziwan,zwan|sc=Latn}}, {{hv|zza|ziwan,zon,zûn}}, {{hv|bal|زوان|tr=zewan}} û {{g|bal|زبان|tr=ziban, zuban}}, {{hv|fa|زبان|tr=zeban}}, {{hv|tg|забон|tr=zabon}}, {{hv|ps|ژبه|tr=žəba}}, {{hv|xpr|𐫙𐫉𐫁𐫀𐫗|tr=izban}}, {{hv|pal|𐫙𐫉𐫇𐫀𐫗|tr=izwan}}, osetî avestayî [[𐬵𐬌𐬰𐬎𐬎𐬁]]‎ (hizuuā), {{hv|sa|जिह्वा|tr=jihvā́}} û [[जुहू]] (juhū́), hindî [[जीभ]] (jībh), {{hv|de|Zunge}}, danmarkî/norwecî ''[[tunge]]'', swêdî/{{hv|is|tunga}}, {{hv|nl|tong}}, {{hv|en|tongue}}, {{hv|ga|teanga}}, {{hv|br|teod}}, {{hv|la|lingua}} (guherîna D bi L din bin tesîra L ya peyva ''[[lingo]]'' anku ''[[alîstin]]'' de), {{hv|it|lingua}}, {{hv|pt|língua}}, {{hv|es|lengua}}, {{hv|fr|langue}}, {{hv|hy|լեզու|tr=lêzû}} (L-ya destpêkê di bin tesîra [[լիզեմ]] /lizêm/ anku ''[[alîstin]]'' de), {{hv|lv|insuwis}}, {{hv|lt|liežùvis}} (L-ya destpêkê di bin tesîra ''[[liežti]]'' anku ''[[alîstin]]'' de), slaviya kevn *''[[ęzỳkъ]]'', rusî/ukraynî/bela{{hv|ru|язы́к|tr=yazýk}}, çekî/slovakî ''[[jazyk]]'', {{hv|pl|język}}. ;{{biçûk|Çavkanî: * {{Cathcart}} * {{Chyet}} * {{Horn|r=144}} * {{MacKenzie|tr=127}} * {{Novák}} * {{Tsabolov}} * {{The Tower of Babel}} }} ==== Bi zaravayên din ==== * {{Z|ckb}}: {{W-|ckb|زمان|tr=ziman}} * {{Z|zza}}: [[ziwan]], [[zon]], [[zûn]] * {{Z|sdh}}: [[ziwan]], [[zuwan]] * {{Z|lki}}: [[zuwan]] * {{Z|hac}}: [[ziwan]], [[zwan]] ==== Werger ==== {{werger-ser|parçeya goştî di devî de|1}} * {{Z|sq}}: {{W+|sq|gjuhë}} * {{Z|de}}: {{W+|de|Zunge}} {{m}} * {{Z|alt}}: {{W-|alt|тил}} * {{Z|an}}: {{W-|an|luenga}} * {{Z|ast}}: {{W+|ast|llingua}} * {{Z|atj}}: {{W-|atj|oterini}} * {{Z|ay}}: {{W-|ay|lajhra}}, {{W+|ay|aru}} * {{Z|az}}: {{W+|az|dil}} * {{Z|bm}}: {{W-|bm|kan}} * {{Z|eu}}: {{W-|eu|mihi}}, {{W-|eu|mingain}} * {{Z|ba}}: {{W-|ba|тел}} * {{Z|bar}}: {{W-|bar|Zung|f}} * {{Z|bem}}: {{W-|bem|ululimi}} * {{Z|br}}: {{W+|br|teod}} {{n}} * {{Z|bg}}: {{W+|bg|език|tr=ezik}} * {{Z|cs}}: {{W+|cs|jazyk}} * {{Z|zh}}: {{W+|zh|舌头|tr=shétou}}, {{W+|zh|舌|tr=shé}} * {{Z|tso-lya}}: {{W-|tso-lya|lussánikh}} * {{Z|cv}}: {{W-|cv|чĕлхе}} * {{Z|dmr}}: {{W-|dmr|leˈmaino}} * {{Z|da}}: {{W+|da|tunge}} {{c}} * {{Z|otd}}: {{W-|otd|jola}} * {{Z|id}}: {{W+|id|lidah}} * {{Z|ar}}: {{W-|ar|لسان|tr=lisan}} * {{Z|hy}}: {{W+|hy|լեզու|tr=lêzû}} * {{Z|eo}}: {{W+|eo|lango}} * {{Z|et}}: {{W+|et|keel}} * {{Z|fa}}: {{W+|fa|زبان|R=zeban}} * {{Z|fo}}: {{W+|fo|tunga}} * {{Z|fi}}: {{W+|fi|kieli}} * {{Z|fr}}: {{W+|fr|langue}} * {{Z|fur}}: {{W-|fur|lenghe|f}} * {{Z|fy}}: {{W-|fy|tonge}} * {{Z|gd}}: {{W-|gd|teanga}} {{m}} * {{Z|gag}}: {{W-|gag|dil}} * {{Z|gl}}: {{W+|gl|lingua}} * {{Z|got}}: {{W-|got|𐍄𐌿𐌲𐌲𐍉|R=tuggō}} {{m}} * {{Z|ka}}: {{W+|ka|ენა|tr=ena}} * {{Z|ht}}: {{W-|ht|lang}} * {{Z|ha}}: {{W+|ha|harshe}} * {{Z|mww}}: {{W-|mww|nplaig}} * {{Z|nl}}: {{W+|nl|tong}} {{m}} * {{Z|io}}: {{W+|io|lango}} * {{Z|en}}: {{W+|en|tongue}} * {{Z|ia}}: {{W+|ia|lingua}} * {{Z|iu}}: {{W-|iu|ᐅᖃᖅ|R=[[uqaq]]}} * {{Z|ist}}: {{W-|ist|lengua}} * {{Z|it}}: {{W+|it|lingua}} {{m}} * {{Z|is}}: {{W+|is|tunga}} {{m}} * {{Z|ja}}: {{W+|ja|舌|R=shita}}, {{W-|ja|ベロ|tr=bero}} * {{Z|krc}}: {{W-|krc|тил}} * {{Z|ca}}: {{W+|ca|llengua}} * {{Z|qu}}: {{W-|qu|qallu}} * {{Z|kvm}}: {{W-|kvm|lɛ̀nyɛ́mə̀}}, {{W-|kvm|ɛ̀nyɛ́mə̀}} * {{Z|ky}}: {{W+|ky|тил}} * {{Z|ko}}: {{W+|ko|혀|tr=hyeo}} * {{Z|kw}}: {{W-|kw|tavas}} * {{Z|co}}: {{W+|co|lingua}} * {{Z|brc}}: {{W-|brc|alala}} * {{Z|kum}}: {{W-|kum|тил}} * {{Z|lv}}: {{W+|lv|mēle}} * {{Z|ln}}: {{W-|ln|lolému}} * {{Z|lt}}: {{W+|lt|liežuvis}} * {{Z|mk}}: {{W+|mk|јазик|tr=jazik}} * {{Z|mg}}: {{W+|mg|lela}} * {{Z|mi}}: {{W-|mi|arero}} * {{Z|hu}}: {{W+|hu|nyelv}} * {{Z|mn}}: {{W+|mn|хэл|tr=khel}} * {{Z|nhn}}: {{W-|nhn|nenepilli}} * {{Z|nio}}: {{W-|nio|сиәде}} * {{Z|ngh}}: {{W-|ngh|ǀ’an}} * {{Z|nog}}: {{W-|nog|тил}} * {{Z|nrf}}: {{W-|nrf|loceis}} * {{Z|no}}: {{W+|no|tunge}} * {{Z|oc}}: {{W+|oc|lenga}} * {{Z|oia}}: {{W-|oia|uhulu}}, {{W-|oia|uhul}} * {{Z|pms}}: {{W-|pms|lenga|f}} * {{Z|myp}}: {{W-|myp|xiipópai}} * {{Z|pl}}: {{W+|pl|język}} * {{Z|pt}}: {{W+|pt|língua}} {{m}} * {{Z|kk}}: {{W+|kk|тіл|tr=til}} * {{Z|rom}}: {{W-|rom|ćhib}} * {{Z|ro}}: {{W+|ro|limbă}} * {{Z|ru}}: {{W+|ru|язык|R=iazyk}} {{n}} * {{Z|se}}: {{W-|se|njuovčča}} * {{Z|sa}}: {{W+|sa|जिह्वा|R=jihvā}} {{m}} * {{Z|sh}}: {{W+|sh|jezik}} * {{Z|sk}}: {{W+|sk|jazyk}} * {{Z|sl}}: {{W+|sl|jezik}} * {{Z|so}}: {{W+|so|carab}} * {{Z|es}}: {{W+|es|lengua}} {{m}} * {{Z|sw}}: {{W+|sw|ulimi}} * {{Z|ss}}: {{W-|ss|lú-lwîmi}} * {{Z|sv}}: {{W+|sv|tunga}} * {{Z|shy}}: {{W-|shy|iles}} * {{Z|zdj}}: {{W-|zdj|ulime}}, {{W-|zdj|louha}} * {{Z|cjs}}: {{W-|cjs|тил}} * {{Z|shh}}: {{W-|shh|a͟ikon}} * {{Z|tl}}: {{W+|tl|dilà}} * {{Z|ta}}: {{W+|ta|நாக்கு|R=nākku}} * {{Z|crh}}: {{W-|crh|til}} * {{Z|tt}}: {{W+|tt|tel}} * {{Z|tr}}: {{W+|tr|dil}} * {{Z|tk}}: {{W+|tk|dil}} * {{Z|kim}}: {{W-|kim|дыл}} * {{Z|tpi}}: {{W-|tpi|tang}} * {{Z|tyv}}: {{W-|tyv|дыл}} * {{Z|ur}}: {{W+|ur|زبان}} * {{Z|uk}}: {{W+|uk|язик|tr=jazyk}} * {{Z|vep}}: {{W-|vep|kelʼ}} * {{Z|vi}}: {{W+|vi|lưỡi}} * {{Z|wa}}: {{W+|wa|linwe|f}} * {{Z|cy}}: {{W+|cy|tafod}} * {{Z|wo}}: {{W-|wo|làmmiñ wi}} * {{Z|kjh}}: {{W-|kjh|тіл}} * {{Z|sah}}: {{W-|sah|тыл}} * {{Z|el}}: {{W+|el|γλώσσα|R=glóssa}} {{m}} {{werger-bin}} {{werger-ser|pergala axiftin û nivîsînê|2}} * {{Z|af}}: {{W+|af|taal}} * {{Z|akz}}: {{W-|akz|naaɬiilka}} * {{Z|sq}}: {{W+|sq|gjuhë}} * {{Z|de}}: {{W+|de|Sprache}} {{m}} * {{Z|an}}: {{W-|an|luenga}} * {{Z|ast}}: {{W+|ast|llingua}} * {{Z|ay}}: {{W+|ay|aru}} * {{Z|bm}}: {{W-|bm|kan}} * {{Z|eu}}: {{W+|eu|hizkuntza}} * {{Z|bar}}: {{W-|bar|Sproch|f}} * {{Z|bem}}: {{W-|bem|ululimi}} * {{Z|br}}: {{W+|br|yezh}} {{m}} * {{Z|bg}}: {{W+|bg|език|tr=ezik}} * {{Z|cs}}: {{W+|cs|jazyk}}, {{W+|cs|řeč}} * {{Z|zh}}: {{W+|zh|语言|tr=yǔyán}} * {{Z|tso-lya}}: {{W-|tso-lya|daritsánikh}} * {{Z|da}}: {{W+|da|sprog}} {{n}} * {{Z|id}}: {{W+|id|bahasa}} * {{Z|ar}}: {{W+|ar|لغة|tr=luẍe<sup>t</sup>}} {{m}}, {{W-|ar|لسان|tr=lisan}} * {{Z|hy}}: {{W+|hy|լեզու|tr=lezou}} * {{Z|eo}}: {{W+|eo|lingvo}} * {{Z|et}}: {{W+|et|keel}} * {{Z|fa}}: {{W+|fa|زبان|R=zeban}} * {{Z|fo}}: {{W+|fo|mál}} * {{Z|fi}}: {{W+|fi|kieli}} * {{Z|vls}}: {{W-|vls|toale}} * {{Z|fr}}: {{W+|fr|langue}} * {{Z|fur}}: {{W-|fur|lenghe|f}} * {{Z|fy}}: {{W-|fy|tonge}}, {{W+|fy|taal}}, {{W-|fy|sprake}} * {{Z|fud}}: {{W-|fud|masau}} * {{Z|gd}}: {{W-|gd|cànan}} {{n}} * {{Z|gl}}: {{W+|gl|lingua}} * {{Z|roa-gal}}: {{W-|roa-gal|laungg}} * {{Z|got}}: {{W-|got|𐍂𐌰𐌶𐌳𐌰|R=razda}} {{m}} * {{Z|gu}}: {{W+|gu|ભાષા}} * {{Z|ka}}: {{W+|ka|ენა|tr=ena}} * {{Z|ht}}: {{W-|ht|lang}} * {{Z|ha}}: {{W+|ha|harshe}}, {{W+|ha|yare}} * {{Z|hi}}: {{W+|hi|भाषा}} * {{Z|nl}}: {{W+|nl|taal}} {{m}} * {{Z|io}}: {{W+|io|linguo}} * {{Z|ang}}: {{W-|ang|spræc}} * {{Z|en}}: {{W+|en|language}}, {{W+|en|tongue}} * {{Z|ia}}: {{W+|ia|lingua}} * {{Z|iu}}: {{W-|iu|ᐅᖃᐅᓯᖅ|R=[[uqausiq]]}} * {{Z|ist}}: {{W-|ist|lengua}} * {{Z|it}}: {{W+|it|lingua}} {{m}}, {{W+|it|linguaggio}} {{n}} * {{Z|is}}: {{W+|is|tunga}} {{m}} * {{Z|ja}}: {{W+|ja|言語|tr=gengo}}, {{W+|ja|言葉|tr=kotoba}} * {{Z|kl}}: {{W-|kl|oqaatsit}} * {{Z|ca}}: {{W+|ca|idioma}}, {{W+|ca|llengua}} * {{Z|qu}}: {{W+|qu|simi}} * {{Z|swb}}: {{W-|swb|luha}} * {{Z|ko}}: {{W+|ko|언어|tr=eoneo}} * {{Z|kw}}: {{W-|kw|yeth}} * {{Z|co}}: {{W+|co|lingua}} * {{Z|la}}: {{W+|la|lingua}} * {{Z|lv}}: {{W+|lv|valoda}} * {{Z|lt}}: {{W+|lt|kalba}} * {{Z|lb}}: {{W+|lb|Sprooch|f}} * {{Z|mk}}: {{W+|mk|јазик|tr=jazik}} * {{Z|mt}}: {{W+|mt|lingwa}} * {{Z|mi}}: {{W+|mi|reo}} * {{Z|hu}}: {{W+|hu|nyelv}} * {{Z|mn}}: {{W+|mn|хэл|tr=khel}} * {{Z|nah}}: {{W+|nah|tlahtolli}} * {{Z|nv}}: {{W-|nv|zaad}} * {{Z|nog}}: {{W-|nog|тил}} * {{Z|no}}: {{W+|no|språk}} * {{Z|oc}}: {{W+|oc|lenga}} * {{Z|pms}}: {{W-|pms|lenga|f}} * {{Z|pdt}}: {{W-|pdt|Sproak}} * {{Z|pl}}: {{W+|pl|język}} * {{Z|pt}}: {{W+|pt|língua}} {{m}}, {{W+|pt|idioma}}, {{W+|pt|linguagem}} * {{Z|kk}}: {{W+|kk|тіл|tr=til}} * {{Z|ro}}: {{W+|ro|limbă|f}} * {{Z|ru}}: {{W+|ru|язык|R=iazyk}} {{n}} * {{Z|se}}: {{W-|se|giella}} * {{Z|sa}}: {{W+|sa|भाषा|R=bāṣā}} {{m}} * {{Z|sh}}: {{W+|sh|jezik}} * {{Z|sk}}: {{W+|sk|jazyk}} * {{Z|sl}}: {{W+|sl|jezik}} * {{Z|so}}: {{W+|so|af}} * {{Z|es}}: {{W+|es|lengua}} {{m}}, {{W+|es|idioma}} {{n}}, {{W+|es|lenguaje}} * {{Z|sw}}: {{W+|sw|lugha}}, {{W+|sw|ulimi}} * {{Z|ss}}: {{W-|ss|lú-lwîmi}} * {{Z|sv}}: {{W+|sv|språk}}, {{W+|sv|mål}} * {{Z|shy}}: {{W-|shy|tutlakt}}, {{W-|shy|tameslayt}} * {{Z|zdj}}: {{W-|zdj|lugha}}, {{W-|zdj|luha}}, {{W-|zdj|ulime}} * {{Z|tg}}: {{W+|tg|забон}} * {{Z|tl}}: {{W+|tl|wika}}, {{W-|tl|lenggwáhe}} * {{Z|ta}}: {{W+|ta|மொழி|R=moḻi}} * {{Z|tt}}: {{W+|tt|tel}} * {{Z|tr}}: {{W+|tr|dil}}, {{W+|tr|lisan}} * {{Z|kim}}: {{W-|kim|дыл}} * {{Z|tpi}}: {{W-|tpi|tok}}, {{W-|tpi|tokples}} * {{Z|ur}}: {{W+|ur|زبان}} * {{Z|uby}}: {{W-|uby|bzɑ}} * {{Z|uk}}: {{W+|uk|мова|tr=mova}} * {{Z|vep}}: {{W-|vep|kelʼ}} * {{Z|vi}}: {{W+|vi|ngôn ngữ}}, {{W+|vi|tiếng}} * {{Z|vo}}: {{W+|vo|pük}} * {{Z|wls}}: {{W-|wls|lea}} * {{Z|wa}}: {{W+|wa|lingaedje|n}}, {{W+|wa|langue|f}} * {{Z|cy}}: {{W+|cy|iaith}} * {{Z|el}}: {{W+|el|γλώσσα|R=glóssa}} {{m}} {{werger-bin}} 0yxek2vvmkczt96mz3qgbpy4t55jb1h 0 3574 6291713 6243173 2026-07-27T20:42:07Z Ghybu 1393 /* Navdêr */ 6291713 wikitext text/x-wiki {{bnr-h|ku|kü|Ku}} == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/kʰuː/}} ** (''[[rojhilatî]]'') {{IPA|ku|/kʰʉː/}} === Hoker === [[Wêne:Sin_mapa.svg|thumb|250px|''kû'' anku çi [[der]]/[[cih]]]] {{hoker|ku}} # [[çi]] [[cih]]î, [[çi]] [[der]]ê, [[kîj]] [[cih]]î, [[kîjan]] [[der]]ê #:''Mala te li '''kû''' ye? #: ''Tu diçî '''kû'''?'' #: ''Ew ji '''kû''' tê''? #: ''Hûn ji '''kû''' ne?'' #:: Hûn xelkê kû derê ne? #: ''Ew çû '''kû'''?'' #: ''Hûn ji '''kû''' hatin?'' #: ''Tu li '''kû''' yî?'' ==== Bi alfabeyên din ==== * {{ku-ar|کوو}} * {{ku-kr|ку}} ==== Formên alternatîv ==== * [[ku]] (3), [[kû derê]], [[kûva]], [[kûve]], [[kûde]], [[kî derê]], [[kîrê]], [[kêrê]], [[kîve]], [[kwîve]], [[kû ve]], [[kû derê]], [[kû de]], [[kî derê]], [[kur]], [[kuva]] ==== Bide ber ==== * [[ku]] * [[ko]] ==== Etîmolojî ==== [[hevreh|Hevreh]]a soranî {{g|ckb|کوێ|tr=-}} (kwê), farisî {{g|fa|کجا}} (ko-[[cih|ca]]) û forma kevnar {{g|fa|کو}} (kû), avestayî [[𐬐𐬎𐬛𐬁‎]] (kudā) sanskrîtî [[कुह]] (kúha) û [[कुत्र]] (kútra), hindî [[किधर]] (kidhar), rusî [[куда́]] (kudá), sirbokroatî [[ку̀да]] / ''[[kùda]]'', ukraynî [[куди́ ]](kudý), çekî ''[[kudy]]'', albanî ''[[ku]]'', latviyayî û lîtwanî ''[[kur]]'', latînî ''[[quō]]'', norwecî ''[[kvar]], [[kor]]'', danmarkî ''[[hvor]]'', swêdî ''[[var]]'', îngilîzî ''[[where]]'', almanî ''[[wo]]'' ... hemû ji {{ji|ine-pro|ku|-}} *''[[kʷu-]], *[[kʷo-]]'' (kû, li kû, çi cih?), têkilî ''[[kʷís]]'' ([[çi]]; [[kî]]). ==== Jê ==== * [[di kû de]] * [[di kû re]] * [[ji kû]] * [[li kû]] ==== Bi zaravayên din ==== * {{Z|ckb}}: {{g|ckb|کوێ}} * {{Z|zza}}: [[kamca]] ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W|af|waar}} * {{Z|sq}}: {{W+|sq|ku}} * {{Z|de}}: {{W+|de|wo}} * {{Z|am}}: {{W-|am|የት|tr=yet}} * {{Z|bm}}: {{W--|bm|min}} * {{Z|bi}}: {{W--|bi|we}} * {{Z|br}}: {{W-|br|pelecʼh}} * {{Z|zh}}: {{W+|zh|哪儿|tr=nǎr}}, {{W+|zh|哪里|tr=nǎli}} * {{Z|dmr}}: {{W--|dmr|ˈladanmaiˈje}} * {{Z|da}}: {{W+|da|hvor}} * {{Z|id}}: {{W+|id|mana}} * {{Z|arz}}: {{W--|arz|فين|tr=fên}} * {{Z|ar}}: {{W|ar|أين}} (eyne) * {{Z|eo}}: {{W+|eo|kie}} * {{Z|fa}}: {{W|fa|کجا|tr=koca}} * {{Z|fo}}: {{W-|fo|hvar}} * {{Z|fi}}: {{W|fi|missä}} (li kû), {{W|fi|mistä}} (ji kû), {{W|fi|mihin}} (kû), {{W|fi|minne}} (kû) * {{Z|fr}}: {{W|fr|où}} * {{Z|got}}: {{W--|got|𐍈𐌰𐍂|tr=ƕar}} * {{Z|ka}}: {{W-|ka|სად|tr=sad}} * {{Z|hi}}: {{W+|hi|कहाँ|tr=kahā̃}} * {{Z|nl}}: {{W+|nl|waar}} * {{Z|he}}: {{W+|he|אי}} * {{Z|idi}}: {{W--|idi|anyo}} * {{Z|io}}: {{W+|io|ube}} * {{Z|en}}: {{W+|en|where}} * {{Z|iu}}: {{W-|iu|ᓇᐅᒃ|tr=[[nauk]]}}, {{W-|iu|ᓇᒥ|tr=[[nami]]}}, {{W-|iu|ᓇᓂ|tr=[[nani]]}} * {{Z|it}}: {{W+|it|dove}}, {{W+|it|ove}} * {{Z|is}}: {{W+|is|hvar}}, {{W+|is|hvert}} * {{Z|ja}}: {{W+|ja|どこ|tr=doko}} * {{Z|ca}}: {{W+|ca|on}} * {{Z|wni}}: {{W--|wni|hapvi}} * {{Z|swb}}: {{W--|swb|hav̄i|tr=havi}} * {{Z|ko}}: {{W+|ko|어디|tr=eodi}} * {{Z|co}}: {{W+|co|duve}}, {{W+|co|induva}} * {{Z|rcf}}: {{W--|rcf|ousa}}, {{W--|rcf|kel-koté}} * {{Z|lkt}}: {{W--|lkt|tokiya}} * {{Z|la}}: {{W+|la|ubi}} * {{Z|lv}}: {{W|lv|kur}} * {{Z|ln}}: {{W-|ln|wápi}} * {{Z|li}}: {{W-|li|woe}} * {{Z|lt}}: {{W|lt|kur}} * {{Z|lb}}: {{W+|lb|wou}} * {{Z|mt}}: {{W+|mt|fejn}} * {{Z|moh}}: {{W--|moh|ka' nón:we}} * {{Z|ngh}}: {{W--|ngh|kidyaxe}} * {{Z|nb}}: {{W+|nb|hvor}} * {{Z|nn}}: {{W+|no|kvar}} * {{Z|oc}}: {{W+|oc|ont}} * {{Z|oia}}: {{W--|oia|te}}, {{W--|oia|tenai}} * {{Z|pis}}: {{W--|pis|we}} * {{Z|pcd}}: {{W--|pcd|d’us}}, {{W--|pcd|d’us qu’}}, {{W--|pcd|adus}}, {{W--|pcd|ù}} * {{Z|pih}}: {{W--|pih|webaut}} * {{Z|pl}}: {{W+|pl|gdzie}} * {{Z|pt}}: {{W+|pt|onde}} * {{Z|kk}}: {{W+|kk|қайда|tr=qayda}} * {{Z|ru}}: {{W+|ru|где|tr=gde}}, {{W+|ru|куда|tr=kuda}} * {{Z|se}}: {{W--|se|gos}} * {{Z|sh}}: {{W+|sh|gdje}} * {{Z|so}}: {{W-|so|halka}} * {{Z|es}}: {{W+|es|dónde}} * {{Z|sv}}: {{W+|sv|var}} * {{Z|shy}}: {{W--|shy|mani}} * {{Z|zdj}}: {{W--|zdj|nɗahu}}, {{W--|zdj|nɗa}}, {{W--|zdj|nɗahupvi}}, {{W--|zdj|nɗapvi}} * {{Z|cjs}}: {{W--|cjs|қайда}} * {{Z|tl}}: {{W-|tl|saán}}, {{W-|tl|násaán}} * {{Z|th}}: {{W+|th|สถานที่|tr=S̄t̄hān thī̀}} * {{Z|crh}}: {{W--|crh|qayerde}}, {{W--|crh|qayda}} * {{Z|tr}}: {{W|tr|nerede}} (li kû), {{W|tr|nereye}} (kû), {{W|tr|nereden}} (ji kû) * {{Z|tpi}}: {{W|tpi|we}} * [[valensî]]: [[aón]] * {{Z|wa}}: {{W|wa|wiss}} * {{Z|kjh}}: {{W--|kjh|хайда}} * {{Z|el}}: {{W+|el|πού|tr=pú}} {{werger-bin}} === Navdêr === {{ku-tewîn-nav|kû|mê}} {{navdêr|ku|z=m}} # Gava pez û bi taybetî mih serê xwe dikine ber hev û li hev kom dibin. #* {{jêder-malper|ku|jêgirtin=Li germê pez ê serê xwe di ber hev ke, bi rê nare. Ew ketina '''kûyê'''.|nivîskar=Mem Xelîkan|url=http://www.mifikan.com/Cand-huner/mem-xelikan.htm|sernav=Germîya Arê Şivanan|malper=mifikan.com|dîrok=2005}} ==== Werger ==== {{werger-ser}} {{werger-bin}} 7vj3sz67t8etn3ohezxqsaweodia23b 6291722 6291713 2026-07-27T21:56:20Z Wikihez 7344 /* Navdêr */ 6291722 wikitext text/x-wiki {{bnr-h|ku|kü|Ku}} == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/kʰuː/}} ** (''[[rojhilatî]]'') {{IPA|ku|/kʰʉː/}} === Hoker === [[Wêne:Sin_mapa.svg|thumb|250px|''kû'' anku çi [[der]]/[[cih]]]] {{hoker|ku}} # [[çi]] [[cih]]î, [[çi]] [[der]]ê, [[kîj]] [[cih]]î, [[kîjan]] [[der]]ê #:''Mala te li '''kû''' ye? #: ''Tu diçî '''kû'''?'' #: ''Ew ji '''kû''' tê''? #: ''Hûn ji '''kû''' ne?'' #:: Hûn xelkê kû derê ne? #: ''Ew çû '''kû'''?'' #: ''Hûn ji '''kû''' hatin?'' #: ''Tu li '''kû''' yî?'' ==== Bi alfabeyên din ==== * {{ku-ar|کوو}} * {{ku-kr|ку}} ==== Formên alternatîv ==== * [[ku]] (3), [[kû derê]], [[kûva]], [[kûve]], [[kûde]], [[kî derê]], [[kîrê]], [[kêrê]], [[kîve]], [[kwîve]], [[kû ve]], [[kû derê]], [[kû de]], [[kî derê]], [[kur]], [[kuva]] ==== Bide ber ==== * [[ku]] * [[ko]] ==== Etîmolojî ==== [[hevreh|Hevreh]]a soranî {{g|ckb|کوێ|tr=-}} (kwê), farisî {{g|fa|کجا}} (ko-[[cih|ca]]) û forma kevnar {{g|fa|کو}} (kû), avestayî [[𐬐𐬎𐬛𐬁‎]] (kudā) sanskrîtî [[कुह]] (kúha) û [[कुत्र]] (kútra), hindî [[किधर]] (kidhar), rusî [[куда́]] (kudá), sirbokroatî [[ку̀да]] / ''[[kùda]]'', ukraynî [[куди́ ]](kudý), çekî ''[[kudy]]'', albanî ''[[ku]]'', latviyayî û lîtwanî ''[[kur]]'', latînî ''[[quō]]'', norwecî ''[[kvar]], [[kor]]'', danmarkî ''[[hvor]]'', swêdî ''[[var]]'', îngilîzî ''[[where]]'', almanî ''[[wo]]'' ... hemû ji {{ji|ine-pro|ku|-}} *''[[kʷu-]], *[[kʷo-]]'' (kû, li kû, çi cih?), têkilî ''[[kʷís]]'' ([[çi]]; [[kî]]). ==== Jê ==== * [[di kû de]] * [[di kû re]] * [[ji kû]] * [[li kû]] ==== Bi zaravayên din ==== * {{Z|ckb}}: {{g|ckb|کوێ}} * {{Z|zza}}: [[kamca]] ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W|af|waar}} * {{Z|sq}}: {{W+|sq|ku}} * {{Z|de}}: {{W+|de|wo}} * {{Z|am}}: {{W-|am|የት|tr=yet}} * {{Z|bm}}: {{W--|bm|min}} * {{Z|bi}}: {{W--|bi|we}} * {{Z|br}}: {{W-|br|pelecʼh}} * {{Z|zh}}: {{W+|zh|哪儿|tr=nǎr}}, {{W+|zh|哪里|tr=nǎli}} * {{Z|dmr}}: {{W--|dmr|ˈladanmaiˈje}} * {{Z|da}}: {{W+|da|hvor}} * {{Z|id}}: {{W+|id|mana}} * {{Z|arz}}: {{W--|arz|فين|tr=fên}} * {{Z|ar}}: {{W|ar|أين}} (eyne) * {{Z|eo}}: {{W+|eo|kie}} * {{Z|fa}}: {{W|fa|کجا|tr=koca}} * {{Z|fo}}: {{W-|fo|hvar}} * {{Z|fi}}: {{W|fi|missä}} (li kû), {{W|fi|mistä}} (ji kû), {{W|fi|mihin}} (kû), {{W|fi|minne}} (kû) * {{Z|fr}}: {{W|fr|où}} * {{Z|got}}: {{W--|got|𐍈𐌰𐍂|tr=ƕar}} * {{Z|ka}}: {{W-|ka|სად|tr=sad}} * {{Z|hi}}: {{W+|hi|कहाँ|tr=kahā̃}} * {{Z|nl}}: {{W+|nl|waar}} * {{Z|he}}: {{W+|he|אי}} * {{Z|idi}}: {{W--|idi|anyo}} * {{Z|io}}: {{W+|io|ube}} * {{Z|en}}: {{W+|en|where}} * {{Z|iu}}: {{W-|iu|ᓇᐅᒃ|tr=[[nauk]]}}, {{W-|iu|ᓇᒥ|tr=[[nami]]}}, {{W-|iu|ᓇᓂ|tr=[[nani]]}} * {{Z|it}}: {{W+|it|dove}}, {{W+|it|ove}} * {{Z|is}}: {{W+|is|hvar}}, {{W+|is|hvert}} * {{Z|ja}}: {{W+|ja|どこ|tr=doko}} * {{Z|ca}}: {{W+|ca|on}} * {{Z|wni}}: {{W--|wni|hapvi}} * {{Z|swb}}: {{W--|swb|hav̄i|tr=havi}} * {{Z|ko}}: {{W+|ko|어디|tr=eodi}} * {{Z|co}}: {{W+|co|duve}}, {{W+|co|induva}} * {{Z|rcf}}: {{W--|rcf|ousa}}, {{W--|rcf|kel-koté}} * {{Z|lkt}}: {{W--|lkt|tokiya}} * {{Z|la}}: {{W+|la|ubi}} * {{Z|lv}}: {{W|lv|kur}} * {{Z|ln}}: {{W-|ln|wápi}} * {{Z|li}}: {{W-|li|woe}} * {{Z|lt}}: {{W|lt|kur}} * {{Z|lb}}: {{W+|lb|wou}} * {{Z|mt}}: {{W+|mt|fejn}} * {{Z|moh}}: {{W--|moh|ka' nón:we}} * {{Z|ngh}}: {{W--|ngh|kidyaxe}} * {{Z|nb}}: {{W+|nb|hvor}} * {{Z|nn}}: {{W+|no|kvar}} * {{Z|oc}}: {{W+|oc|ont}} * {{Z|oia}}: {{W--|oia|te}}, {{W--|oia|tenai}} * {{Z|pis}}: {{W--|pis|we}} * {{Z|pcd}}: {{W--|pcd|d’us}}, {{W--|pcd|d’us qu’}}, {{W--|pcd|adus}}, {{W--|pcd|ù}} * {{Z|pih}}: {{W--|pih|webaut}} * {{Z|pl}}: {{W+|pl|gdzie}} * {{Z|pt}}: {{W+|pt|onde}} * {{Z|kk}}: {{W+|kk|қайда|tr=qayda}} * {{Z|ru}}: {{W+|ru|где|tr=gde}}, {{W+|ru|куда|tr=kuda}} * {{Z|se}}: {{W--|se|gos}} * {{Z|sh}}: {{W+|sh|gdje}} * {{Z|so}}: {{W-|so|halka}} * {{Z|es}}: {{W+|es|dónde}} * {{Z|sv}}: {{W+|sv|var}} * {{Z|shy}}: {{W--|shy|mani}} * {{Z|zdj}}: {{W--|zdj|nɗahu}}, {{W--|zdj|nɗa}}, {{W--|zdj|nɗahupvi}}, {{W--|zdj|nɗapvi}} * {{Z|cjs}}: {{W--|cjs|қайда}} * {{Z|tl}}: {{W-|tl|saán}}, {{W-|tl|násaán}} * {{Z|th}}: {{W+|th|สถานที่|tr=S̄t̄hān thī̀}} * {{Z|crh}}: {{W--|crh|qayerde}}, {{W--|crh|qayda}} * {{Z|tr}}: {{W|tr|nerede}} (li kû), {{W|tr|nereye}} (kû), {{W|tr|nereden}} (ji kû) * {{Z|tpi}}: {{W|tpi|we}} * [[valensî]]: [[aón]] * {{Z|wa}}: {{W|wa|wiss}} * {{Z|kjh}}: {{W--|kjh|хайда}} * {{Z|el}}: {{W+|el|πού|tr=pú}} {{werger-bin}} === Navdêr === {{ku-tewîn-nav|kû|mê}} {{navdêr|ku|z=m}} # [[gav|Gava]] [[pez|pez]] û [[bi taybetî]] [[mih|mih]] [[ser|serê]] [[xwe|xwe]] dikine [[ber|ber]] [[hev|hev]] û [[li hev]] [[kom bûn|kom dibin]]. #* {{jêder-malper|ku|jêgirtin=Li germê pez ê serê xwe di ber hev ke, bi rê nare. Ew ketina '''kûyê'''.|nivîskar=Mem Xelîkan|url=http://www.mifikan.com/Cand-huner/mem-xelikan.htm|sernav=Germîya Arê Şivanan|malper=mifikan.com|dîrok=2005}} ==== Werger ==== {{werger-ser}} {{werger-bin}} hr94si8nn41wwwlf6kogu0plv6l2gfs dayik 0 3683 6291798 6262173 2026-07-28T02:32:42Z Ghybu 1393 forma bangkirinê "dayikê" tê gotin ? 6291798 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-dayik.wav|Deng|Bidlîs}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|dayik|mê|alt.bang.yj=dayê}} [[Wêne:Souci maternel.jpg|thumb|Dayikek û [[kur]]ê ([[law]]ê) xwe.]] {{navdêr|ku|z=m}} # {{f|ku|malbat}} [[jin|Jin]]a ku mirov jê çêbûye. #: {{mk|ku|Ew ne '''dayika''' min e; meta min e.}} # [[jin|Jin]]a ku [[bi kêmî]] [[zarok]]ek heye. #: {{mk|ku|Ew berî hefteyekê bû '''dayik'''.}} ==== Bi alfabeyên din ==== * {{ku-ar|دایک}} ==== Formên alternatîv ==== {{kol3|ku | da | daya | daye | dayîk | dayk | deyik | deyîk | deyk | dak | dê | di | dî }} ==== Nêzîk ==== {{kol3|ku | ma | mad | mak }} ==== Têkildar ==== * {{g|ku|bav}} ==== Jê ==== {{kol3|ku | dayikbûn<q:navdêr> | dayikane | dayikî | dayikîtî | dayiktî | dapîr | dêbav }} ==== Etîmolojî ==== {{şêwexirab}} * {{ji|ine-pro|ku|-}}: *'''d<sup>h</sup>e-i-''' ("mêtin / mijandin") :{{ji|ira-pro||-}}: *'''da<sup>5</sup>''' ("---") ::{{ae}}: '''daenu'''- ("---") ::{{pal}}: '''dāyak''' ("---") ::{{ho}}: '''dīnu''' ("---") ::{{fa}}: '''dāye''' ("hevşîre / ebe") ::{{ os}}: '''daejyn''' ("---") ::{{kmr}}: '''dayik''', '''da''', '''deyk''', '''dê''' ::{{hac}}: '''dāyāna''' ("---") ... ::{{zza}}: '''dāya''') {{ir}} ::{{lor}}: '''dāya''' ("dayik") ::{{tal}}: '''dāya''' ("dayik") :{{sa}}: '''dhāyati''' ("mêtin / mijandin") :{{hy}}: '''dayeak''' ("hevşîre / ebe") :{{la}}: '''fellare''' ("mêtin / mijandin") :{{el}}: '''thēlē''' ("memik / çiçik / guhan") ... :<font style="font-size:10px">'''Çavkanî:''' [[Wt/diq/Horn|Horn p.119]], [[Wt/diq/Cheung|Cheung p.47]], [[Wt/diq/Watkins|Watkins p.18]], [[Wt/diq/Etymonline|Etymonline]]</font> ==== Werger ==== {{werger-ser}} * {{Z|ab}}: {{W-|ab|ан}} * {{Z|ace}}: {{W-|ace|ma}}, {{W-|ace|mak}} * {{Z|ady}}: {{W-|ady|ны}} * {{Z|aa}}: {{W-|aa|ina}} * {{Z|af}}: {{W+|af|moeder}}, {{W+|af|ma}} * {{Z|xag}}: {{W-|xag|𐕎𐔴}} * {{Z|akk}}: {{W-|akk|𒂼|ts=ummu|3=f}} * {{Z|ak}}: {{W-|ak|ɛna}} * {{Z|akl}}: {{W-|akl|ina}} * {{Z|sq}}: {{W+|sq|nënë}}, {{W+|sq|ëmë}}, {{W+|sq|mëmë|m}} * {{Z|ale}}: {{W-|ale|anax}} * {{Z|pdc}}: {{W-|pdc|Mudder|m}}, {{W-|pdc|Mammi|m}} * {{Z|de}}: {{W+|de|Mutter|m}} *: {{Z|gsw}}: {{W-|gsw|Mueter|m}} *: {{Z|bar}}: {{W-|bar|muadda}} * {{Z|am}}: {{W+|am|እናት|m}} * {{Z|ami}}: {{W-|ami|ina}} * {{Z|ani}}: {{W-|ani|ила}} * Apaçî: *: {{Z|apm}}: {{W-|apm|-má}} *: {{Z|apw}}: {{W-|apw|bimaa}}, {{W-|apw|bąą}} * {{Z|an}}: {{W+|an|mai|m}} * {{Z|arc}}: *: {{Z|aii}}: {{W-|aii|ܝܸܡܵܐ|m|tr=yimma}}, {{W-|aii|ܝܵܠܘܿܕܬܵܐ|m|tr=yalodta}} *: {{Z|syc}}: {{W-|syc|ܐܡܐ|m|tr=ʾemmā}}, {{W-|syc|ܝܠܘܕܬܐ|m|tr=yālōḏtā}} *: Aramiya cihû: {{W-|arc|אִמָּא|m|tr=ʾimmā}} * {{Z|rup}}: {{W-|rup|mamã|m}}, {{W-|rup|mumã|m}} * {{Z|aer}}: {{W-|aer|meye}} * {{Z|as}}: {{W-|as|মা}}, {{W-|as|আই}} * {{Z|asl}}: {{W-|asl|ina}} * {{Z|ast}}: {{W+|ast|madre|m}}, {{W+|ast|ma|m}} * {{Z|av}}: {{W-|av|эбел}}, {{W-|av|баба}}, {{W-|av|буба}} * {{Z|ay}}: {{W-|ay|mama}} * {{Z|ain}}: {{W-|ain|ハポ|tr=hapo}} * {{Z|az}}: {{W+|az|ana}} * {{Z|ban}}: {{W-|ban|ina}}, {{W-|ban|biyang}} * {{Z|eu}}: {{W+|eu|ama}} * {{Z|ba}}: {{W-|ba|әсәй}}, {{W-|ba|әсә}} * {{Z|bbc}}: {{W-|bbc|ina}} * {{Z|be}}: {{W-|be|ма́ці|m}}, {{W-|be|ма́тка|m}} * {{Z|bal}}: {{W-|bal|مات|tr=mát}}, {{W-|bal|ماس|tr=más}} * {{Z|bem}}: {{W-|bem|mayo}} * {{Z|bn}}: {{W+|bn|আম্মা}}, {{W-|bn|আম্মু}}, {{W+|bn|মাতা}}, {{W+|bn|মা}} * {{Z|bqi}}: {{W-|bqi|دا|tr=dâ}} * {{Z|bhw}}: {{W-|bhw|ina}} * {{Z|bcl}}: {{W-|bcl|ina}} * {{Z|bhp}}: {{W-|bhp|ina}} * {{Z|bla}}: {{W-|bla|iksísst}} * {{Z|brx}}: {{W-|brx|आइ}}, {{W-|brx|बिमा}} * {{Z|lbk}}: {{W-|lbk|ína}} * {{Z|bor}}: {{W-|bor|tʃe}} * {{Z|br}}: {{W+|br|mamm|m}} * {{Z|kxd}}: {{W-|kxd|babu}}, {{W-|kxd|mama}} * {{Z|bdk}}: {{W-|bdk|диде}} * {{Z|bug}}: {{W-|bug|ᨕᨗᨊ|tr=ina}} * {{Z|bg}}: {{W-|bg|ма́йка|m}} * {{Z|my}}: {{W+|my|အမေ}}, {{W+|my|အမိ}}, {{W+|my|မိခင်}}, {{W+|my|မေမေ}} * {{Z|bua}}: {{W-|bua|эхэ}} * {{Z|dgc}}: {{W-|dgc|ína}} * {{Z|dz}}: {{W-|dz|ཨའི}} * {{Z|cyo}}: {{W-|cyo|ina}} * {{Z|ce}}: {{W-|ce|нана}} * {{Z|cs}}: {{W+|cs|matka|m}} * {{Z|chr}}: {{W-|chr|ᎤᏂᏥ}} * {{Z|chn}}: {{W-|chn|mama}}, {{W-|chn|naha}} * {{Z|ny}}: {{W-|ny|mayi}} * {{Z|cic}}: {{W-|cic|ishk'}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|母親|tr=mou5 can1}}, {{W-|yue|母|tr=mou5}}, {{W-|yue|阿媽}}, {{W-|yue|媽媽}} *: {{Z|dng}}: {{W-|dng|ма}}, {{W-|dng|мучин}}, {{W-|dng|мама}}, {{W-|dng|нён}}, {{W-|dng|чиннён}} *: {{Z|gan}}: {{W-|gan|姆媽|tr=m1 ma}} *: {{Z|hak}}: {{W-|hak|母親|tr=mû-chhîn}}, {{W-|hak|娘親|tr=ngiòng-chhîn}}, {{W-|hak|阿姆|tr=â-mê}} *: {{Z|cmn}}: {{W+|cmn|母親|tr=mǔqīn}}, {{W+|cmn|母|tr=mǔ}}, {{W+|cmn|媽媽|tr=māma}}, {{W+|cmn|娘|tr=niáng}}, {{W+|cmn|媽|tr=mā}} *: {{Z|cdo}}: {{W-|cdo|依媽|tr=ĭ-mă}}, {{W-|cdo|依奶|tr=ĭ-nā̤}}, {{W-|cdo|娘嬭}}, {{W-|cdo|娘妳|tr=nòng-nā̤}} *: {{Z|nan}}: {{W+|nan|娘|tr=niâ}}, {{W-|nan|娘親|tr=niû-chhin}}, {{W-|nan|母親|tr=bó-chhin, bú-chhin}}, {{W+|nan|阿姆|tr=a-ḿ}} *: {{Z|wuu}}: {{W-|wuu|姆媽}}, {{W-|wuu|媽媽}} *: {{Z|hsn}}: {{W-|hsn|姆媽|tr=m1 ma1}} * {{Z|ckt}}: {{W-|ckt|ытԓя|tr=ətla}}, {{W-|ckt|ытԓьа|tr=ətlʔa}} * {{Z|cv}}: {{W-|cv|анне}} * {{Z|chk}}: {{W-|chk|in}} * {{Z|dak}}: {{W-|dak|iná}} * {{Z|dlm}}: {{W-|dlm|nina|m}} * {{Z|da}}: {{W+|da|moder}}, {{W+|da|mor|g}} * {{Z|dar}}: {{W-|dar|неш}} * {{Z|dv}}: {{W-|dv|މަނމަ}} * {{Z|sce}}: {{W-|sce|ekie}} * {{Z|dtp}}: {{W-|dtp|tina}} * {{Z|ovd}}: {{W-|ovd|muna|m}}, {{W-|ovd|mųor|m}} * {{Z|avd}}: {{W-|avd|ننه|tr=nane}} * {{Z|id}}: {{W+|id|ibu}}, {{W+|id|bunda}} * {{Z|ar}}: {{W+|ar|أُمّ|m}}, {{W+|ar|وَالِدَة|m}} * {{Z|hy}}: {{W+|hy|մայր}}, {{W+|hy|մամա}} * {{Z|myv}}: {{W-|myv|ава}}, {{W-|myv|ава}} * {{Z|eo}}: {{W+|eo|patrino}} * {{Z|et}}: {{W+|et|ema}} * {{Z|ett}}: {{W-|ett|𐌀𐌕𐌉}} * {{Z|eve}}: {{W-|eve|энин}} * {{Z|evn}}: {{W-|evn|энин}} * {{Z|ext}}: {{W-|ext|mairi}} * {{Z|xfa}}: {{W-|xfa|mate}} * {{Z|peo}}: {{W-|peo|𐎶𐎠𐎫𐎠|ts=mātā}} * {{Z|fa}}: {{W+|fa|مادر|tr=mâdar}}, {{W+|fa|مامان|m|tr=mâmân}} * {{Z|ddg}}: {{W-|ddg|nalu}} * {{Z|fo}}: {{W+|fo|móðir|m}}, {{W+|fo|mamma|m}} * {{Z|xpg}}: {{W-|xpg|μητερε}} * {{Z|fj}}: {{W+|fj|tina}} * {{Z|fi}}: {{W+|fi|äiti}} * {{Z|fr}}: {{W+|fr|mère|m}} * {{Z|fur}}: {{W-|fur|mari}} * {{Z|frr}}: *: {{Z|frr}}: {{W-|frr|mam|m|}} *: {{Z|frr}}: {{W-|frr|mäm|g}} *: {{Z|frr}}: {{W-|frr|Mem|g}} *: {{Z|frr}}: {{W-|frr|Mooter|g}} * {{Z|stq}}: {{W-|stq|Muur}} * {{Z|fy}}: {{W+|fy|mem|m}} * {{Z|gd}}: {{W+|gd|màthair|m}} * {{Z|gl}}: {{W+|gl|nai|m}}, {{W+|gl|mai|m}}, {{W+|gl|madre|m}} * {{Z|glk}}: {{W-|glk|مر|tr=mar}} * {{Z|got}}: {{W-|got|𐌰𐌹𐌸𐌴𐌹|m}} * {{Z|gu}}: {{W-|gu|મા|m}} * {{Z|gup}}: {{W-|gup|karrang}} * {{Z|ka}}: {{W+|ka|დედა}} * {{Z|gn}}: {{W+|gn|sy}} * {{Z|haw}}: {{W-|haw|makuahine}} * {{Z|ha}}: {{W+|ha|uwa}}, {{W-|ha|inna}} * {{Z|hi}}: {{W+|hi|माता|m}}, {{W-|hi|मां|m}}, {{W+|hi|मादर|m}}, {{W+|hi|वालिदा|m}} * {{Z|meu}}: {{W-|meu|ina}} * {{Z|hit}}: {{W-|hit|𒀭𒈾𒀸}} * {{Z|nl}}: {{W+|nl|moeder|m}} * {{Z|esh}}: {{W-|esh|ننیه|tr=naniya}} * {{Z|iba}}: {{W-|iba|indai}}, {{W-|iba|ina}} * {{Z|he}}: {{W-|he|אֵם|m|tr=em}} * {{Z|io}}: {{W+|io|matro}} * {{Z|ig}}: {{W-|ig|nne}} * {{Z|ang}}: {{W-|ang|mōdor|m}} * {{Z|en}}: {{W+|en|mother}}, {{t|en|mom}}, {{t|en|mum}} * {{Z|izh}}: {{W-|izh|emä}}, {{W-|izh|emo}} * {{Z|inh}}: {{W-|inh|нана}} * {{Z|ia}}: {{W+|ia|matre}} * {{Z|iu}}: {{W-|iu|ᐊᓈᓇ}} * {{Z|ik}}: {{W-|ik|aana}}, {{W-|ik|aaka}} * {{Z|ill}}: {{W-|ill|ina'}} * {{Z|ga}}: {{W+|ga|máthair|m}} *: {{Z|sga}}: {{W-|sga|máthir}} * {{Z|isd}}: {{W-|isd|ina}} * {{Z|ist}}: {{W-|ist|mare|m}} * {{Z|ruo}}: {{W-|ruo|måie|m}} * {{Z|it}}: {{W+|it|madre|m}} * {{Z|itv}}: {{W-|itv|ina}} * {{Z|ivv}}: {{W-|ivv|ina}} * {{Z|is}}: {{W+|is|mamma|m}}, {{W+|is|móðir|m}} * {{Z|ja}}: {{W+|ja|お母さん|tr=おかあさん, okāsan}}, {{W+|ja|母|tr=はは, haha}}, {{W+|ja|ママ|tr=mama}}, {{W+|ja|お袋|tr=おふくろ, o-fukuro}} * {{Z|anq}}: {{W-|anq|kaja}} * {{Z|jra}}: {{W-|jra|amĭ}} * {{Z|jv}}: {{W-|jv|ibu}} * {{Z|jje}}: {{W-|jje|어멍}} * {{Z|quc}}: {{W-|quc|chuch}} * {{Z|kzj}}: {{W-|kzj|ina}} * {{Z|tbd}}: {{W-|tbd|naora}} * {{Z|kl}}: {{W-|kl|anaana}} * {{Z|xal}}: {{W-|xal|эк}} * {{Z|xbr}}: {{W-|xbr|ina}} * {{Z|rkt}}: {{W-|rkt|মাও|tr=maó}} * {{Z|kne}}: {{W-|kne|iná}} * {{Z|kn}}: {{W+|kn|ತಾಯಿ}} * {{Z|pam}}: {{W-|pam|ima}}, {{W-|pam|indu}} * {{Z|krc}}: {{W-|krc|ана}} * {{Z|kyj}}: {{W-|kyj|ina}} * {{Z|krl}}: {{W-|krl|emä}} * {{Z|kyh}}: {{W-|kyh|táat}}, {{W-|kyh|ihkuus}} * {{Z|csb}}: {{W-|csb|mëma|m}}, {{W+|csb|mac}} * {{Z|ca}}: {{W+|ca|mare|m}} * {{Z|qu}}: {{W+|qu|mama}} * {{Z|ks}}: {{W-|ks|موج}}, {{W-|ks|مٲج}} * {{Z|ky}}: {{W+|ky|эне}} * {{Z|si}}: {{W+|si|අම්මා}} * {{Z|com}}: {{W-|com|pia}} * {{Z|koi}}: {{W-|koi|мам}} * {{Z|kpv}}: {{W-|kpv|мам}}, {{W-|kpv|ань}} * {{Z|kvh}}: {{W-|kvh|ina}} * {{Z|okm}}: {{W-|okm|어〮미〮}} * {{Z|ko}}: {{W+|ko|엄마}}, {{W+|ko|어머니}}, {{W+|ko|어머님}}, {{W+|ko|에미}}, {{W+|ko|어미}} * {{Z|kw}}: {{W-|kw|mamm|m}}, {{W-|kw|dama|m}} * {{Z|co}}: {{W+|co|mamma|m}} * {{Z|rop}}: {{W-|rop|motha}} * {{Z|kum}}: {{W-|kum|ана}} * {{Z|kwk}}: {{W-|kwk|a̱bas}} * {{Z|lbe}}: {{W-|lbe|нину}} * {{Z|lkt}}: {{W-|lkt|iná}} * {{Z|ltg}}: {{W-|ltg|muote}} * {{Z|la}}: {{W+|la|māter|m}}, {{W-|la|genetrix|m}} * {{Z|lv}}: {{W+|lv|māte|m}} * {{Z|lo}}: {{W+|lo|ແມ່}} * {{Z|lzz}}: {{W-|lzz|დიდა}} * {{Z|lez}}: {{W-|lez|диде}} * {{Z|lti}}: {{W-|lti|ina}} * {{Z|kmk}}: {{W-|kmk|ina}} * {{Z|lij}}: {{W-|lij|moæ|m}} * {{Z|lt}}: {{W-|lt|motė|m}}, {{W+|lt|motina|m}} * {{Z|liv}}: {{W-|liv|jemā}}, {{W-|liv|ǟma}} * {{Z|lmo}}: {{W-|lmo|mamma|m}}, {{W-|lmo|mader}} * {{Z|khb}}: {{W-|khb|ᦶᦙᧈ}} * {{Z|lg}}: {{W-|lg|maama}} * {{Z|luy}}: {{W-|luy|mai}} * {{Z|lb}}: {{W+|lb|Mamm|m}} * {{Z|luo}}: {{W-|luo|mama}} * {{Z|lut}}: {{W-|lut|sk'ʷuy}} * {{Z|mdh}}: {{W-|mdh|ina}} * {{Z|mkz}}: {{W-|mkz|ina}} * {{Z|mak}}: {{W-|mak|ina}} * {{Z|mk}}: {{W-|mk|ма́јка|m}} * {{Z|mg}}: {{W+|mg|reny}} * {{Z|ml}}: {{W+|ml|അമ്മ}}, {{W+|ml|മാതാവ്}}, {{W+|ml|തള്ള}} * {{Z|ms}}: {{W+|ms|ibu}}, {{W-|ms|emak}} * {{Z|mt}}: {{W-|mt|omm}}, {{W-|mt|mamà}}, {{W-|mt|ma}} * {{Z|mnc}}: {{W-|mnc|ᡝᠮᡝ}}, {{W-|mnc|ᡝᠨᡳᠶᡝ}}, {{W-|mnc|ᠠᠵᠠ}}, {{W-|mnc|ᠨᠠᡳᠨᠠᡳ}} * {{Z|mnk}}: {{W-|mnk|naa}} * {{Z|gv}}: {{W-|gv|moir}} * {{Z|msk}}: {{W-|msk|ina}} * {{Z|mns-nor}}: {{W-|mns-nor|ся̄нь}} * {{Z|mi}}: {{W-|mi|matua}} {{W+|mi|wahine}}, {{W-|mi|ewe}}, {{W-|mi|whaea}}, {{W-|mi|whaene}}, {{W-|mi|kowhaea}}, {{W-|mi|kōkara}}, {{W-|mi|ūkaipō}} * {{Z|mrw}}: {{W-|mrw|ina'}}, {{W-|mrw|misina}} * {{Z|mr}}: {{W+|mr|आई|m}}, {{W-|mr|माता|m}} * {{Z|mhr}}: {{W-|mhr|ава}} * {{Z|mrc}}: {{W-|mrc|n'ay}} * {{Z|yua}}: {{W-|yua|na'}} * {{Z|ifu}}: {{W-|ifu|iná}} * {{Z|mzn}}: {{W-|mzn|مار|tr=mâr}} * {{Z|gun}}: {{W-|gun|xy}} * {{Z|hu}}: {{W+|hu|anya}} * {{Z|xmf}}: {{W-|xmf|დიდა}} * {{Z|mwv}}: {{W-|mwv|ina}} * {{Z|mer}}: {{W-|mer|mama}} * {{Z|egy}}: {{W-egy|mwt|m|h=mwt-t-B1}} * {{Z|mvi}}: {{W-|mvi|アンナ|tr=anna}} * {{Z|min}}: {{W-|min|mande}} * {{Z|mng}}: {{W-|mng|may}} * {{Z|mdf}}: {{W-|mdf|тядя}} * {{Z|mn}}: {{W+|mn|эх}}, {{W+|mn|ээж}} * {{Z|mtq}}: {{W-|mtq|mễ}} * {{Z|wlc}}: {{W-|wlc|mama}} * {{Z|nah}}: {{W+|nah|nantli}} * {{Z|naq}}: {{W-|naq|ǁgûs}} * {{Z|gld}}: {{W-|gld|энин}} * {{Z|ncn}}: {{W-|ncn|ina}} * {{Z|nv}}: {{W-|nv|amá}} * {{Z|nds}}: *: {{Z|nds-nl}}: {{W-|nds-nl|moder}} *: {{Z|nds-de}}: {{W-|nds-de|Moder|m}} * {{Z|ne}}: {{W+|ne|आमा|m}} * {{Z|nxg}}: {{W-|nxg|ina}} * {{Z|nia}}: {{W-|nia|ina}} * {{Z|niv}}: {{W-|niv|ымк}}, {{W-|niv|ымык}}, {{W-|niv|ымка}}, {{W-|niv|ымыка}} * {{Z|nrf}}: {{W-|nrf|méthe|m}} * {{Z|no}}: *: {{Z|no}}: {{W+|no|mor|n|m}}, {{W+|no|mamma|n}}, {{W-|no|moder|n}} *: {{Z|no}}: {{W+|no|mor|m}} * {{Z|ood}}: {{W-|ood|je'e}} * {{Z|cst}}: {{W-|cst|ká̄na 'ek'án̄an}} * {{Z|oj}}: {{W-|oj|nimaamaa}}, {{W-|oj|ninga}} * {{Z|oc}}: {{W+|oc|mair|m}}, {{W+|oc|maire|m}} * {{Z|or}}: {{W+|or|ମା}} * {{Z|om}}: {{W-|om|haadha}} * {{Z|os}}: {{W-|os|мад}}, {{W-|os|мадӕ}} * {{Z|ota}}: {{W-|ota|مادر|tr=mâder}}, {{W-|ota|ام|tr=ümm}}, {{W-|ota|والده|tr=vâlide}} * {{Z|ug}}: {{W+|ug|ئانا}}, {{W+|ug|ئاپا}} * {{Z|uz}}: {{W+|uz|ona}} *: Kirîlî: {{W+|uz|она}} * {{Z|pac}}: {{W-|pac|a-i}}, {{W-|pac|icán}} * {{Z|pwn}}: {{W-|pwn|ina}} * {{Z|pag}}: {{W-|pag|iná}} * {{Z|plh}}: {{W-|plh|ina}} * {{Z|uun}}: {{W-|uun|ina}} * {{Z|ps}}: {{W+|ps|مور|m|tr=mor}} * {{Z|myp}}: {{W-|myp|baíxi}} * {{Z|pjt}}: {{W-|pjt|ngunytju}} * {{Z|pdt}}: {{W-|pdt|Mutta|m}} * {{Z|pox}}: {{W-|pox|motai|m}} * {{Z|pl}}: {{W+|pl|matka|m}}, {{W+|pl|mama|m}}, {{W+|pl|mać|m}}, {{W+|pl|mamusia}}, {{W+|pl|matula}}, {{W+|pl|matuchna}}, {{W+|pl|mateczka}}, {{W+|pl|mamuśka}}, {{W+|pl|matuś}}, {{W-|pl|matuśka}} * {{Z|pt}}: {{W+|pt|mãe|m}} * {{Z|pa}}: {{W-|pa|ਮਾਂ|m}}, {{W-|pa|ਮਾਤਾ|m}} * {{Z|kek}}: {{W-|kek|naʼ}} * {{Z|kk}}: {{W-|kk|ана}} * {{Z|cop}}: *: Bohaîrî: {{W-|cop|ⲙⲁⲩ|m}} *: Sahîdî: {{W-|cop|ⲙⲁⲁⲩ|m}} * {{Z|rah}}: {{W-|rah|আয়া|tr=aya}} * {{Z|rad}}: {{W-|rad|amĭ}} * {{Z|rm}}: {{W-|rm|mamma|m}}, {{W-|rm|mumma|m}}, {{W-|rm|mama|m}}, {{W-|rm|moma|m}} * {{Z|rom}}: {{W-|rom|daj|m}} *: {{Z|rmw}}: {{W-|rmw|daj|m}} * {{Z|ro}}: {{W+|ro|mamă|m}}, {{W+|ro|maică|m}} * {{Z|ru}}: {{W+|ru|мать|m}}, {{W-|ru|ма́ма|m}}, {{W-|ru|ма́тушка|m}}, {{W-|ru|мама́ша|m}} * {{Z|rue}}: {{W-|rue|ма́ти|m}}, {{W-|rue|ма́терь|m}}, {{W-|rue|ма́ма|m}} * {{Z|hvn}}: {{W-|hvn|ina}} * {{Z|xsy}}: {{W-|xsy|ina}} * Samî: *: {{Z|smn}}: {{W-|smn|enni}} *: {{Z|sjd}}: {{W-|sjd|е̄ннҍ}} *: {{Z|smj}}: {{W-|smj|ieddne}} *: {{Z|se}}: {{W-|se|eadni}} *: {{Z|sms}}: {{W-|sms|jeäˊnn}} *: {{Z|sma}}: {{W-|sma|tjidtjie}} * {{Z|sm}}: {{W-|sm|tinā}} * {{Z|sa}}: {{W+|sa|अम्बा|m}} {{W-|sa|मातर|m}}, {{W+|sa|अक्का|m}} * {{Z|sat}}: {{W-|sat|ᱮᱝᱜᱚ}} * {{Z|sc}}: {{W-|sc|mama|m}}, {{W-|sc|mamma|m}}, {{W-|sc|immamma|m}} * {{Z|sas}}: {{W-|sas|ina}} * {{Z|ceb}}: {{W-|ceb|inahan}} * {{Z|scn}}: {{W+|scn|matri|m}} * {{Z|sid}}: {{W-|sid|ama}} * {{Z|csm}}: {{W-|csm|ˀytá·-}} * {{Z|ski}}: {{W-|ski|ina}} * {{Z|smr}}: {{W-|smr|ina}} * {{Z|sd}}: {{W-|sd|ماء|tr=māʾu}}, {{W-|sd|اما|tr=āmā}} * {{Z|srn}}: {{W-|srn|m'ma}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|мат|m}}, {{W-|sh|мати|m}}, {{W-|sh|мајка|m}}, {{W-|sh|родитељица|m}}, {{W-|sh|рођеница|m}}, {{W-|sh|матер|m}} *: Latînî: {{W+|sh|mat|m}}, {{W+|sh|mati|m}}, {{W+|sh|majka|m}}, {{W+|sh|roditeljica|m}}, {{W-|sh|rođenica|m}}, {{W+|sh|mater|m}} * {{Z|syl}}: {{W-|syl|ꠝꠣ}} * {{Z|sco}}: {{W-|sco|mither}}, {{W-|sco|moder}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|мати|m}} *: Glagolîtîk: {{W-|cu|ⰿⰰⱅⰻ|m}} * {{Z|orv}}: {{W-|orv|мати|m}} * {{Z|sk}}: {{W+|sk|matka|m}} * {{Z|sl}}: {{W+|sl|mati|m}} * {{Z|so}}: {{W+|so|hooyo}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|maś|m}}, {{W-|dsb|maśeŕ|m}}, {{W-|dsb|maśerka|m}}, {{W-|dsb|mama|m}}, {{W-|dsb|maminka|m}} *: {{Z|hsb}}: {{W+|hsb|mać|m}} * {{Z|st}}: {{W+|st|mme}} * {{Z|es}}: {{W+|es|madre|m}} * {{Z|su}}: {{W-|su|biang}}, {{W-|su|indung}} * {{Z|sva}}: {{W-|sva|დედე}} * {{Z|sw}}: {{W+|sw|mzazi}}, {{W+|sw|mama}} * {{Z|sv}}: {{W+|sv|mor|g}}, {{W+|sv|moder|g}}, {{W+|sv|mamma|g}} * {{Z|xsr}}: {{W-|xsr|འ་མ|tr=hama}} * {{Z|zdj}}: {{W-|zdj|nya}} * {{Z|cjs}}: {{W-|cjs|иче|tr=içe}}, {{W-|cjs|эне|tr=ene}} * {{Z|tyz}}: {{W-|tyz|嗒}}, {{W-|tyz|嗒}}, {{W-|tyz|嗩}} * {{Z|tab}}: {{W-|tab|дада}} * {{Z|tg}}: {{W+|tg|модар}} * {{Z|tl}}: {{W+|tl|ina}} * {{Z|ty}}: {{W-|ty|metua vahine}} * {{Z|tly}}: {{W-|tly|ننه|tr=nana}} * {{Z|ta}}: {{W+|ta|அம்மா}}, {{W+|ta|தாய்}}, {{W+|ta|அன்னை}}, {{W+|ta|யாய்}} * {{Z|roa-tar}}: {{W-|roa-tar|mamme|m}} * {{Z|rif}}: {{W-|rif|yemma|m}} * {{Z|tsg}}: {{W-|tsg|ina}} * {{Z|th}}: {{W+|th|แม่}}, {{W+|th|มารดา}} * {{Z|te}}: {{W+|te|తల్లి}}, {{W+|te|అమ్మ|m}} * {{Z|tft}}: {{W-|tft|yaya}} * {{Z|crh}}: {{W-|crh|ana}} * {{Z|tt}}: {{W+|tt|ана}}, {{W+|tt|әни}} * {{Z|tet}}: {{W-|tet|inan}} * {{Z|ssf}}: {{W-|ssf|ina}} * {{Z|ti}}: {{W-|ti|ኣደ}} * {{Z|tr}}: {{W+|tr|anne}}, {{W+|tr|ana}} * {{Z|tk}}: {{W-|tk|eje}} *: Kirîlî: {{W-|tk|еҗе}} * {{Z|bo}}: {{W-|bo|ཨ་མ}}, {{W-|bo|ཨ་མ་ལགས}} * {{Z|tpi}}: {{W-|tpi|mama}}, {{W-|tpi|mami}} * {{Z|to}}: {{W-|to|fa'ē}} * {{Z|xto}}: {{W-|xto|mācar}} * {{Z|txb}}: {{W-|txb|mācer}} * {{Z|tn}}: {{W-|tn|mme}} * {{Z|tpn}}: {{W-|tpn|sy}}, {{W-|tpn|si}} * {{Z|tyv}}: {{W-|tyv|ава}}, {{W-|tyv|авам}}, {{W-|tyv|авай}}, {{W-|tyv|ийе}} * {{Z|udi}}: {{W-|udi|нана}} * {{Z|udm}}: {{W-|udm|анай}} * {{Z|uga}}: {{W-|uga|𐎜𐎎}} * {{Z|ur}}: {{W-|ur|ماتا|m|tr=mātā}}, {{W-|ur|ماں|m|tr=mā̃}}, {{W+|ur|مادر|m|tr=mādar}}, {{W+|ur|والدہ|m|tr=vālidā}} * {{Z|uk}}: {{W-|uk|ма́ти|m}}, {{W-|uk|ма́ма|m}}, {{W-|uk|ма́тір|m}}, {{W-|uk|не́ня}}, {{W-|uk|мату́ся|m}}, {{W-|uk|ма́мця|m}} * {{Z|vec}}: {{W+|vec|mare|m}} * {{Z|vep}}: {{W-|vep|mam}} * {{Z|vi}}: {{W+|vi|mẹ}}, {{W+|vi|má}}, {{W+|vi|mạ}}, {{W+|vi|mệ}}, {{W+|vi|mợ}}, {{W+|vi|bầm}}, {{W+|vi|u}}, {{W+|vi|nạ}}, {{W+|vi|đẻ}}, {{W+|vi|cái}} * {{Z|vo}}: {{W+|vo|mot}} * {{Z|wa}}: {{W+|wa|mere|m}} * {{Z|cy}}: {{W+|cy|mam|m}} * {{Z|wrh}}: {{W-|wrh|gunhi}} * {{Z|wlo}}: {{W-|wlo|ina}} * {{Z|wo}}: {{W-|wo|ndey}}, {{W+|wo|yaay}} * {{Z|km}}: {{W+|km|ម្ដាយ}}, {{W+|km|ម៉ែ}} * {{Z|xh}}: {{W-|xh|unyoko}}, {{W-|xh|unina}} * {{Z|yxg}}: {{W-|yxg|budang}} * {{Z|sah}}: {{W-|sah|ийэ}} * {{Z|yag}}: {{W-|yag|tapi}} * {{Z|yi}}: {{W-|yi|מוטער|m}}, {{W-|yi|מאַמע|m}} * {{Z|yo}}: {{W-|yo|ìyá}}, {{W-|yo|abiyamọ}}, {{W-|yo|iye}}, {{W-|yo|yèyé}}, {{W-|yo|màmá}}, {{W-|yo|mọ́mì}} * {{Z|esu}}: {{W-|esu|aana}} * {{Z|el}}: {{W+|el|μητέρα|m}}, {{W+|el|μάνα|m}} *: Kevn: {{W-|grc|μήτηρ|m}} * {{Z|zea}}: {{W-|zea|moeder|m}}, {{W-|zea|moer|m}} * {{Z|za}}: {{W-|za|ma}}, {{W-|za|maj}}, {{W+|za|meh}}, {{W-|za|mih}}, {{W-|za|caq}} * {{Z|ase}}: {{W-|ase|5@Chin-ThumbBack Contact}} * {{Z|zu}}: {{W+|zu|umama|c1a|c2a}}, {{W-|zu|unyoko|c1a|c2a}}, {{W-|zu|unina|c1a|c2a}} * {{Z|nmn}}: {{W-|nmn|qáe}}{{werger-bin}} :{{werger çavkanî|en|mother|oldid=75650634|beş=Ev qismê Wergerê}} lwm3jsmcs3r1sh55vbwyscuryww4jr4 lawik 0 3734 6291749 6243201 2026-07-27T23:13:59Z Ghybu 1393 /* Navdêr 1 */ 6291749 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|lawik|nêr|alt.çem.yj=l'''ê'''wik}} [[Wêne:Du şirin.jpg|thumb|250px|Du '''lawik'''. (1)]] {{navdêr|ku|z=n}} # [[law|Law]]ekî [[binavkirî]], [[ew]] [[law]], [[kurrik]]. #: {{hevmane|ku|kurik}} #* {{jêder|ku|jêgirtin='''Lêwik''' xwest tiştekî ji bavê xwe re bibêje, Iê eskeran nehiştin, bi milên wî girtin û ew kişandin hundur.|{{Jêgirtin/Firat Cewerî/Girtî}}}} #* {{jêder|ku|jêgirtin=Spîkên çavên '''lêwik''' zer bûbûn, çavên wî carina fireh dibûn û dihatin girtin.|{{Jêgirtin/Firat Cewerî/Girtî}}}} # [[yar]], [[berdilî]], [[evîndar]] #* {{bêmînak|ku}} ==== Formên alternatîv ==== * {{hw|ku|lawk}} ==== Jê ==== {{kol2|ku | lawikî | lawikbêj | lawikbêjî }} ==== Têkildar ==== * {{g|ku|lawij}} * {{g|ku|lawje}} ==== Etîmolojî ==== Ji {{paş|ku|law|-ik}}. ==== Werger ==== {{werger-bnr|zarokên nêr|law}} {{werger-bnr|yar, berdilî, evîndar|law}} {{bend}} === Navdêr 2 === {{ku-tewîn-nav|lawik|mê}} {{navdêr|ku|z=m}} # {{f|ku|muzîk}} [[cûn|Cûn]]ek [[stran]]ên [[kurdî]] yên li ser [[qehremanî|qehremaniyê]] ne. #* {{bêmînak|ku}} ==== Etîmolojî ==== Hevreh bi gotina ''law'' ("lawik, zêmar") a ''Fehlewiyat''a Serdemên Navîn. Dibe bi {{q|ku|law}} yek bibe. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W|tr|müzikli hikaye}} {{werger-bin}} sujpybd1t78hskcivmhd5bjafvq2yeh welat 0 3870 6291751 6234867 2026-07-27T23:15:35Z Ghybu 1393 /* Navdêr */ 6291751 wikitext text/x-wiki {{bnr-h|Welat}} == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/wɛˈɫɑːt/}}, {{IPAchar|/wɛˈɫɑːtˁ/}} * {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-welat.wav|Deng|Wan}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|welat|nêr|alt.çem.yj=wel'''ê'''t}} {{navdêr|ku|z=n}} # {{bêmane|ku}} #: {{hevmane|ku|niştiman|dewlet|weten|memleket|war|dewal}} #: {{mk|ku|Kurdistan '''welatê''' kurdan e.}} #* {{jêder-kovar|ku|jêgirtin=Welatînî di hundirê me de agirekî miqedes e. Pêta wî agirî ji me re her tiştên '''welêt''' dide hez kirin. Ji lewre, di ber çavên me de ax, av, çiya, deşt, dar û kevirên '''welatê''' me ji yên '''welatên''' din spehîtir, xweştir û şêrîntir in.|kovar={{w|Hawar (kovar)|Hawar}}|sal=1932|hejmar=9|sernav=Welat, welatînî û al}} #* {{jêder|ku|jêgirtin='''Welatê''' min tu yî bûka cîhan î<br>Hemî bax û bihuşt û mêrg û kanî <br>Şepal û şeng û şox û naz û gewr î<br>Gelek şêrîn û rind û pir ciwan î <br>Serî taca Selahedînê Kurd î<br>Enî roj e di birca asîmanî <br>Du birhên te kevanê Rustemê Zal<br>Du zulfên te ji tîrên qehremanî|[[w:Cegerxwîn|Cegerxwîn]]}} ==== Bi alfabeyên din ==== * {{ku-ar|وه‌لات}} ==== Jê ==== {{kol3|ku | welat berdan<q:lêker> | welatberdan<q:navdêr> | bêwelat | bêwelatî | hemwelatî | hevwelatî | hevwelatîtî | welatevîn | welathez | welathezî | welatî | welatînî | welatparêz | welatparêzane | welatparêzî | welatperwer | welatperwerî | welatî | welatîbûn | welatîtî | welatvan | welatvanî }} ==== Bide ber ==== {{kol3|ku | ax | bajar | cih | cîhan | der | dever | dinya | eyalet | gund | herêm | navçe | parêzgeh | parzemîn | wîlayet | xak | zemîn }} ==== Etîmolojî ==== Ji {{q|ku|wîlayet}} ji {{deyn|ar|ku|ولاية|cuda=وِلَايَة|tr=wilaye<sup>t</sup>}}. Hevreha {{hv|ckb|وڵات|tr=wiłat}}. Ji eynî rehî: {{q|ku|walî}}, {{q|ku|welayet}}, {{q|ku|eyalet}}, {{q|ku|ewliya}}, {{q|ku|welî}}, {{q|ku|mewla}}, {{q|ku|mewalî}}, {{q|ku|mal}}... ;{{biçûk|Çavkanî: * {{Chyet|r=642}} }} ==== Bi zaravayên din ==== * {{Z|ckb}}: {{W-|ckb|وڵات|tr=wiłat}} * {{Z|zza}}: {{W+|zza|welat}} ==== Werger ==== {{werger-ser}} * {{Z|ab}}: {{W-|ab|аҳәынҭқарра}} * {{Z|ady}}: {{W-|ady|хэку}} * {{Z|af}}: {{W+|af|land}} * {{Z|sq}}: {{W+|sq|atdhe}}, {{W+|sq|shtet|n}} * {{Z|de}}: {{W+|de|Land|nt}}; {{W+|de|Staat|n}}; {{W+|de|Vaterland|nt}} * {{Z|ast}}: {{W+|ast|país|n}} * {{Z|av}}: {{W-|av|улка}} * {{Z|ain}}: {{W-|ain|モシㇼ|tr=mosir}} * {{Z|az}}: {{W+|az|ölkə}}, {{W+|az|dövlət}}, {{W+|az|məmləkət}} * {{Z|eu}}: {{W-|eu|herrialde}} * {{Z|ba}}: {{W-|ba|ил}}, {{W-|ba|дәүләт}} * {{Z|be}}: {{W+|be|краі́на|m}}, {{W+|be|дзяржа́ва|m}} * {{Z|bn}}: {{W+|bn|দেশ}}, {{W+|bn|রাষ্ট্র}} * Berberî: *: {{Z|shi}}: {{W-|shi|tamazirt|m}} * {{Z|br}}: {{W+|br|bro|m}} * {{Z|bg}}: {{W+|bg|страна́|m}}, {{W+|bg|роди́на|m}}, {{W+|bg|държа́ва|m}} * {{Z|my}}: {{W+|my|နိုင်ငံ}} * {{Z|ce}}: {{W-|ce|мохк}}, {{W-|ce|махкалла}} * {{Z|cs}}: {{W+|cs|země|m}}, {{W+|cs|stát|n}} * {{Z|chr}}: {{W-|chr|ᎠᏰᏟᎤᏙᏢᏒ}} * {{Z|ny}}: {{W-|ny|dziko}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|國家}} *: {{Z|dng}}: {{W-|dng|гоцзя}} *: {{Z|cmn}}: {{W+|cmn|國家}} *: {{Z|mnp}}: {{W-|mnp|國家}} *: {{Z|nan}}: {{W+|nan|國家|tr=kok-ka}} *: {{Z|wuu}}: {{W-|wuu|國家}} * {{Z|ckt}}: {{W-|ckt|нутэнут|tr=nutėnut}}, {{W-|ckt|государство|tr=gosudarstvo}} * {{Z|da}}: {{W+|da|land|nt}} * {{Z|id}}: {{W+|id|negara}}, {{W+|id|bangsa}} * {{Z|ar}}: {{W+|ar|بَلَد|m}}, {{W+|ar|وَطَن|n}} *: {{Z|arz}}: {{W-|arz|بلد|m|tr=balad}}, {{W-|arz|وطن|n|tr=waṭan}} * {{Z|hy}}: {{W+|hy|երկիր}}, {{W+|hy|պետություն}} * {{Z|eo}}: {{W-|eo|ŝtato}}, {{W+|eo|lando}} * {{Z|et}}: {{W+|et|maa}}, {{W+|et|riik}} * {{Z|fa}}: {{W+|fa|کِشوَر|tr=kešvar}}, {{W+|fa|میهَن|tr=mihan}}, {{W+|fa|سَرزَمین|tr=sarzamin}} * {{Z|fo}}: {{W-|fo|land}} * {{Z|fi}}: {{W+|fi|maa}}, {{W+|fi|valtio}} * {{Z|fr}}: {{W+|fr|pays|n}}, {{W+|fr|contrée|m}} * {{Z|stq}}: {{W-|stq|Lound}} * {{Z|fy}}: {{W+|fy|lân|nt}} * {{Z|gl}}: {{W+|gl|país|n}} * {{Z|gu}}: {{W+|gu|દેશ}} * {{Z|ka}}: {{W-|ka|ქვეყანა}} * {{Z|ht}}: {{W-|ht|peyi}} * {{Z|haw}}: {{W-|haw|kaumokuʻāina}} * {{Z|hi}}: {{W+|hi|देश|n}}, {{W+|hi|राष्ट्र|n}} * {{Z|nl}}: {{W+|nl|land|nt}} * {{Z|he}}: {{W+|he|אֶרֶץ|m|tr=érets}}, {{W+|he|מְדִינָה|m|tr=m'diná}} * {{Z|io}}: {{W+|io|lando}} * {{Z|ang}}: {{W+|ang|land|nt}} * {{Z|en}}: {{W+|en|country}} * {{Z|izh}}: {{W-|izh|maa}}, {{W-|izh|riikki}} * {{Z|ia}}: {{W-|ia|pais}} * {{Z|ga}}: {{W-|ga|tír|m}} * {{Z|it}}: {{W+|it|paese|n}}, {{W+|it|nazione|m}}, {{W+|it|patria|m}}, {{W+|it|stato|n}} * {{Z|is}}: {{W+|is|land|nt}}, {{W+|is|ríki|nt}} * {{Z|ja}}: {{W+|ja|国|tr=くに, kuni}}, {{W+|ja|国家|tr=こっか, kokka}} * {{Z|jra}}: {{W-|jra|čar}} * {{Z|jv}}: {{W+|jv|negara}} * {{Z|kbd}}: {{W-|kbd|хэку}} * {{Z|kl}}: {{W-|kl|nunaat}} * {{Z|kn}}: {{W+|kn|ದೇಶ}}, {{W+|kn|ರಾಷ್ಟ್ರ}} * {{Z|csb}}: {{W-|csb|państwò|nt}} * {{Z|ca}}: {{W+|ca|país|n}} * {{Z|qu}}: {{W+|qu|suyu}} * {{Z|ks}}: {{W-|ks|مُلک}} * {{Z|ky}}: {{W+|ky|өлкө}}, {{W+|ky|мамлекет}} * {{Z|si}}: {{W+|si|රට}} * {{Z|ko}}: {{W+|ko|나라}}, {{W+|ko|국가}} * {{Z|gcf}}: {{W-|gcf|péyi}} * {{Z|kum}}: {{W-|kum|пачалыкъ}}, {{W-|kum|уьлке}} * {{Z|lld}}: {{W-|lld|paeje}} * {{Z|la}}: {{W+|la|terra|m}}, {{W+|la|natio|m}}, {{W+|la|patria|m}} * {{Z|lv}}: {{W+|lv|valsts|n}}, {{W+|lv|zeme|m}} * {{Z|lo}}: {{W-|lo|ປະເທດ}}, {{W+|lo|ເມືອງ}}, {{W+|lo|ຊາດ}} * {{Z|lez}}: {{W-|lez|уьлкве}} * {{Z|lij}}: {{W-|lij|pàize}} * {{Z|lt}}: {{W+|lt|valstybė|m}}, {{W+|lt|šalis|m}}, {{W+|lt|kraštas|n}} * {{Z|khb}}: {{W-|khb|ᦵᦙᦲᧂ}}, {{W-|khb|ᨾᩮᩥ᩠ᨦ}} * Luri: *: {{Z|lrc}}: {{W-|lrc|ولات|tr=wlạt}} * {{Z|lb}}: {{W+|lb|Land|nt}}, {{W+|lb|Staat|n}} * {{Z|lut}}: {{W-|lut|swatixʷtəd}} * {{Z|mk}}: {{W-|mk|држава|m}}, {{W-|mk|земја|m}}, {{W-|mk|нација|m}} * {{Z|mg}}: {{W+|mg|tany}} * {{Z|ml}}: {{W+|ml|രാജ്യം}} * {{Z|ms}}: {{W+|ms|negara}}, {{W+|ms|nasional}} * {{Z|mt}}: {{W-|mt|pajjiż|n}} * {{Z|mnc}}: {{W-|mnc|ᡤᡠᡵᡠᠨ|tr=gurun}} * {{Z|mr}}: {{W+|mr|देश|n}} * {{Z|hu}}: {{W+|hu|ország}} * {{Z|xmf}}: {{W-|xmf|ქიანა}}, {{W-|xmf|ქიჸანა}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|улс}}, {{W+|mn|гүрэн}}, {{W+|mn|орон}} * {{Z|nv}}: {{W-|nv|kéyah}} * {{Z|nds}}: {{W-|nds|land|nt}} * {{Z|ne}}: {{W+|ne|देश}} * {{Z|nrf}}: {{W-|nrf|pays|n}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|land|nt}} *: {{Z|nn}}: {{W-|nn|land|nt}} * {{Z|oj}}: {{W-|oj|aki}}, {{W-|oj|akiin|p}} * {{Z|oc}}: {{W+|oc|país|n}} * {{Z|ota}}: {{W-|ota|ایل|tr=il}} * {{Z|ug}}: {{W-|ug|دۆلەت}}, {{W-|ug|مەملىكەت}} * {{Z|uz}}: {{W+|uz|mamlakat}} * {{Z|blk}}: {{W-|blk|ခမ်းထီ}} * {{Z|bxd}}: {{W-|bxd|mau³¹}}, {{W-|bxd|maŋ³¹}}, {{W-|bxd|maŋ³¹ tɛ̃⁵⁵}}, {{W-|bxd|kɔ³¹kja⁵⁵}} * {{Z|ps}}: {{W-|ps|مملکت|n|tr=mamlakat}} * {{Z|pdt}}: {{W-|pdt|Launt|nt}} * {{Z|roa-poi}}: {{W-|roa-poi|poes|n}}, {{W-|roa-poi|péyis|n}} * {{Z|pl}}: {{W+|pl|kraj|m-in}}, {{W+|pl|państwo|nt}} * {{Z|pt}}: {{W+|pt|país|n}}, {{W+|pt|nação|m}}, {{W+|pt|países|p}} * {{Z|pa}}: {{W-|pa|ਦੇਸ਼}}, {{W-|pa|ਮੂਲਕ}}, {{W-|pa|ਰਾਸ਼ਟਰ}} * {{Z|kk}}: {{W-|kk|ел}}, {{W-|kk|мемлекет}} * {{Z|cop}}: {{W-|cop|ⲭⲱⲣⲁ|m}}, {{W-|cop|ⲕⲁϩⲓ|n}} * {{Z|rm}}: {{W-|rm|pajais|n}} * {{Z|rom}}: {{W-|rom|them|n}} * {{Z|ro}}: {{W+|ro|țară|m}}, {{W+|ro|națiune}}, {{W+|ro|stat|nt}}, {{W+|ro|patrie|m}} * {{Z|ru}}: {{W+|ru|страна́|m}}, {{W+|ru|госуда́рство|nt}}, {{W+|ru|держа́ва|m}}, {{W+|ru|край|n}} * {{Z|rue}}: {{W-|rue|краї́на|m}} * {{Z|nai-spt}}: {{W-|nai-spt|tiichám}} * {{Z|sa}}: {{W+|sa|देश|n}}, {{W+|sa|राष्ट्र|n}} * {{Z|sd}}: {{W-|sd|ملڪ}} * {{Z|sco}}: {{W-|sco|kintra}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|землꙗ|m}}, {{W-|cu|страна|m}} * {{Z|orv}}: {{W-|orv|землꙗ|m}}, {{W-|orv|краина|m}} * {{Z|sk}}: {{W+|sk|krajina|m}}, {{W+|sk|štát|n}} * {{Z|sl}}: {{W+|sl|država|m}} * {{Z|es}}: {{W+|es|país|n}} * {{Z|sw}}: {{W-|sw|U-|c11|c14}}, {{W+|sw|dola|c9|c10}}, {{W+|sw|inchi|c9|c10}} * {{Z|sv}}: {{W+|sv|land|nt}} * {{Z|tg}}: {{W+|tg|давлат}}, {{W-|tg|мамлакат}}, {{W+|tg|кишвар}} * {{Z|tl}}: {{W+|tl|bansa}} * {{Z|ta}}: {{W+|ta|தேசம்}} * {{Z|twf}}: {{W-|twf|pǫ̏’óna}} * {{Z|th}}: {{W+|th|ประเทศ}}, {{W+|th|เมือง}}, {{W+|th|ชาติ}}, {{W+|th|รัฐ}} * {{Z|te}}: {{W+|te|దేశము}} * {{Z|crh}}: {{W-|crh|memleket}} * {{Z|tt}}: {{W+|tt|ил}}, {{W+|tt|дәүләт}} * {{Z|tr}}: {{W+|tr|ülke}}, {{W+|tr|memleket}}, {{W+|tr|il}}, {{W+|tr|el}}, {{W+|tr|devlet}} * {{Z|tk}}: {{W+|tk|ülke}}, {{W-|tk|döwlet}}, {{W-|tk|watan}} * {{Z|tpi}}: {{W-|tpi|kantri}} * {{Z|aoz}}: {{W-|aoz|pah}} * {{Z|uga}}: {{W-|uga|𐎈𐎆𐎚}} * {{Z|ur}}: {{W-|ur|ملک|n|tr=mulk}}, {{W-|ur|دیش|n|tr=deś}}, {{W-|ur|راشٹر|n|tr=rāṣṭra}} * {{Z|uk}}: {{W+|uk|краї́на|m}}, {{W+|uk|держа́ва|m}} * {{Z|vi}}: {{W+|vi|quốc gia}}, {{W+|vi|đất nước}} * {{Z|vo}}: {{W+|vo|län}} * {{Z|wa}}: {{W+|wa|payis|n}} * {{Z|cy}}: {{W+|cy|gwladwriaeth}} * {{Z|wo}}: {{W+|wo|réew}} * {{Z|km}}: {{W+|km|ស្រុក}}, {{W+|km|ប្រទេស}} * {{Z|yi}}: {{W-|yi|מדינה|m|tr=medine}} * {{Z|yo}}: {{W-|yo|orílẹ̀-èdè}} * {{Z|el}}: {{W+|el|χώρα|m}} *: Kevn: {{W-|grc|χώρα|m}} * {{Z|za}}: {{W-|za|guekgya}} {{werger-bin}} :{{werger çavkanî|beş=Ev tabloya wergerê|en|country|oldid=75552904}} 2ymloqrmzzf1aqrrzyrcyfuaab0cgz0 xelat 0 4697 6291766 5890403 2026-07-28T00:15:03Z Ghybu 1393 /* Navdêr */ mn => m/n 6291766 wikitext text/x-wiki {{Binêre herwiha|Xelat}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-xelat.wav|Deng|Bidlîs}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|xelat|mê}} {{ku-tewîn-nav|xelat|nêr}} [[Wêne:Medals.jpg|thumb|250pix|çend [[medalye]] ku wek xelat tên dayîn]] {{navdêr|ku|z=m/n}}, {{t-ya nerm}} # tişta/ê kesek [[wergirtin|werdigire]] dema [[biserketin|bi ser dikeve]]<br>(bi taybetî di [[pêşbazî|pêşbaziyekê]] ango [[pêşbirk]]ekê de) #: ''Xelata yekem 1 000 dolar e.'' (Yê bibe yekem dê hezar dolaran wergire.) #* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=[[ba#Daçek 2|Ba]] mujde û emr û berat</br>Nîşan hinarin hem '''xelat'''</br>Şehzadeya gulgûn qeba}} ==== Bi alfabeyên din ==== * {{ku-ar|خه‌لات}} ==== Bikaranîn ==== * Zayenda vê peyvê di [[kurmanciya navendî]] û [[kurmanciya rojavayî|rojavayî]] de bi piranî mê ye lê di [[kurmanciya rojhilatî]] de bi gelemperî nêr e. ==== Bide ber ==== * {{g|ku|xalet}} ==== Jê ==== {{kol3|ku|cure=Jê |xelat bûn<q:lêker> |xelat dan<q:lêker> |welat girtin |xelat kirin |xelat girtin |xelat danîn |xelatbûn<q:navdêr> |xelatdan<q:navdêr> |welatgirtin |xelatkirin |xelatwergirtin |xelatgirtin |xelatdanîn |xelatgirtî<q:rengdêr> |xelatbexş |xelatbexşî |xelatdar |xelatdarî |xelatder |xelatder |xelatgir |welatgirî |xelatî |xelatwergir |welatwergirî }} ==== Etîmolojî ==== Hevreha {{hv|ckb|خه‌ڵات}}, {{hv|fa|خلعت|tr=xel'et|w=[[eba]]yê xelatkirinê}}, {{hv|ota|خلعت}}, {{hv|az|xələt|w=xilat, [[keftan]]}}, {{hv|uz|xalat}}, {{hv|ru|халат}}, {{hv|tr|halat}}... Hemû ji {{deyn|ar|ku|خِلْعَة}} ([[eba]]yê xelatkirinê) ji {{g|ar|خَلَعَ}} ([[ji xwe kirin]], [[ji ber xwe kirin]], [[veşelandin]]). Di zimanên din de wateya "[[eba]], [[kiras]]" yan "ebayê/cilê xelatkirinê" dide lê kurdî (kurmancî û soranî) de wateya "padaşt, xelat" wergirtiye. Bo guherîna ''-i-'' bi ''-e-'' (x'''i'''l'et > x'''e'''lat bidin ber ''[[welat]]'' û ''ʕe'' anku عە (xil'''ʕe'''t > ''xel'''a'''t'') bidin ber ''[['eql]]'' > ''[[aqil]]''. {{biçûk| ;Çavkanî: * {{Chyet}}, * {{Tsabolov}} }} ==== Bi zaravayên din ==== * {{Z|ckb}}: {{W-|ckb|خه‌ڵات}} Bi kurmancî : psin. ==== Werger ==== {{werger-ser}} * {{Z|sq}}: {{W+|sq|çmim|n}} * {{Z|de}}: {{W+|de|Preis|n}} * {{Z|as}}: {{W-|as|বঁটা}} * {{Z|az}}: {{W+|az|mükafat}} * {{Z|be}}: {{W-|be|прэ́мія|m}}, {{W-|be|прыз|n}}, {{W-|be|узнагаро́да|m}}, {{W-|be|нагаро́да|m}} * {{Z|bn}}: {{W-|bn|প্রাইজ}}, {{W-|bn|পুরষ্কার}} * {{Z|bg}}: {{W+|bg|награ́да|m}}, {{W+|bg|пре́мия|m}} * {{Z|my}}: {{W+|my|ဆု}} * {{Z|cs}}: {{W+|cs|cena|m}}, {{W-|cs|ocenění|nt}} * {{Z|chr}}: {{W-|chr|ᎠᏓᎪᎾᏙᏗ}} * {{Z|zh}}: *: {{Z|cmn}}: {{W+|cmn|獎品|tr=jiǎngpǐn}}, {{W+|cmn|獎金|tr=jiǎngjīn}} * {{Z|da}}: {{W-|da|præmie|g}}, {{W+|da|pris|g}} * {{Z|ar}}: {{W-|ar|جَائِزَة|m}}, {{W-|ar|مُكَافَأَة|m}} * {{Z|hy}}: {{W+|hy|մրցանակ}} * {{Z|et}}: {{W-|et|auhind}} * {{Z|fa}}: {{W+|fa|جایزه|tr=jâyeze}}, {{W+|fa|مکافات|tr=mokâfât}}, {{W+|fa|انعام|tr=en'âm}} * {{Z|fi}}: {{W+|fi|palkinto}} * {{Z|fr}}: {{W+|fr|prix|n}} * {{Z|ka}}: {{W-|ka|პრიზი}}, {{W+|ka|ჯილდო}} * {{Z|hi}}: {{W+|hi|इनाम|n}}, {{W+|hi|पुरस्कार|n}} * {{Z|nl}}: {{W+|nl|prijs|n}}, {{W+|nl|beloning|m}}, {{W+|nl|premie|m}} * {{Z|he}}: {{W+|he|פְּרָס|n|tr=pras}} * {{Z|en}}: {{W+|en|prize}} * {{Z|ga}}: {{W-|ga|duais|m}} * {{Z|it}}: {{W+|it|premio|n}} * {{Z|ja}}: {{W+|ja|賞|tr=しょう, shō}} * {{Z|ca}}: {{W+|ca|premi|n}} * {{Z|ky}}: {{W+|ky|байге}}, {{W-|ky|приз}}, {{W+|ky|сыйлык}} * {{Z|ko}}: {{W+|ko|상}} * {{Z|ltg}}: {{W-|ltg|duovaņs}}, {{W-|ltg|prizs}} * {{Z|la}}: {{W-|la|praemium|nt}} * {{Z|lv}}: {{W-|lv|balva|m}}, {{W-|lv|prēmija|m}} * {{Z|lo}}: {{W-|lo|ລາງວັນ}} * {{Z|lt}}: {{W-|lt|prizas|n}}, {{W-|lt|premija|m}} * {{Z|mk}}: {{W-|mk|награда|m}} * {{Z|mi}}: {{W-|mi|puiaki}}, {{W-|mi|tohu puiaki}}, {{W-|mi|paraihe}} * {{Z|hu}}: {{W+|hu|díj}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|шагнал}} *: Mongolî: {{W-|mn|ᠱᠠᠩᠨᠠᠯ}} * {{Z|nds}}: {{W+|nds|Pries}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|premie|n}}, {{W+|nb|pris|n}} * {{Z|oc}}: {{W+|oc|prèmi|n}} * {{Z|uz}}: {{W+|uz|mukofot}}, {{W+|uz|sovrin}} * {{Z|ps}}: {{W+|ps|انعام|n|tr=en'ãm}} * {{Z|pl}}: {{W+|pl|nagroda|m}} * {{Z|pt}}: {{W+|pt|prêmio|n}}, {{W+|pt|prémio|n}} * {{Z|kk}}: {{W-|kk|жүлде}}, {{W-|kk|марапат}}, {{W-|kk|сыйлық}}, {{W-|kk|бәйге}} * {{Z|ro}}: {{W+|ro|premiu|nt}} * {{Z|ru}}: {{W+|ru|пре́мия|m}}, {{W+|ru|приз|n}}, {{W+|ru|награ́да|m}} * {{Z|sa}}: {{W+|sa|मीढ|nt}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|на̑града|m}} *: Latînî: {{W+|sh|nȃgrada|m}} * {{Z|sk}}: {{W+|sk|cena|m}} * {{Z|sl}}: {{W+|sl|nagrada|m}} * {{Z|es}}: {{W+|es|premio|n}} * {{Z|sv}}: {{W+|sv|pris|nt}}, {{W+|sv|vinst|g}} * {{Z|tg}}: {{W+|tg|мукофот}}, {{W-|tg|ҷоиза}}, {{W+|tg|инъом}} * {{Z|th}}: {{W+|th|รางวัล}} * {{Z|tt}}: {{W+|tt|бүләк}} * {{Z|tr}}: {{W+|tr|ödül}}, {{W+|tr|mükafat}} * {{Z|tk}}: {{W+|tk|baýrak}} * {{Z|ur}}: {{W+|ur|انعام|n|tr=in'ām}} * {{Z|uk}}: {{W+|uk|пре́мія|m}}, {{W-|uk|приз|n}}, {{W-|uk|нагоро́да|m}} * {{Z|vi}}: {{W+|vi|giải thưởng}}, {{W+|vi|giải}} * {{Z|cy}}: {{W+|cy|gwobr|m}} * {{Z|km}}: {{W+|km|រង្វាន់}} * {{Z|yi}}: {{W-|yi|פּרײַז|n}}, {{W-|yi|פּרעמיע|m}}, {{W-|yi|פּריז|n}} * {{Z|el}}: {{W+|el|βραβείο|nt}} *: Kevn: {{W-|grc|βραβεῖον|nt}}, {{W-|grc|ἆθλον|nt}} {{werger-bin}} :{{werger çavkanî|en|prize|beş=Ev qismê Wergerê|oldid=75653361}} ckhm22vexmm992zx0ntememg1twai5j ça 0 5215 6291825 6035287 2026-07-28T10:52:40Z Ghybu 1393 6291825 wikitext text/x-wiki {{bnr-h|-ça|ca|Ca}} == {{ziman|ku}} == {{şêwexirab}} === Navdêr === {{navdêr|ku|z=}} # {{bnr|çay}} #* {{bêmînak|ku}} # {{bnr|co}} #* {{bêmînak|ku}} Ava ji çem biçûktir û ji coyê mezintir e. (Xerzan) mîn: çaya jor, ça xwarê, ça Hebo ==== Etîmolojî ==== Binere: [[çay]] === Hoker=== {{hoker|ku|z=}} # [[çawa]], bi [[çi]] [[awa]] #* {{bêmînak|ku}} ==== Etîmolojî ==== Binere: [[çawa]] ==== Werger ==== {{werger-ser}} * {{Z|fa}}: {{W+|fa|چگونه}}, {{W+|fa|چطور}} * {{Z|tr}}: {{W+|tr|çay}} {{werger-bin}} == {{ziman|fr}} == === Bilêvkirin === : {{ku-tîp|sa}} * {{deng|fr|LL-Q150 (fra)-Poslovitch-ça.wav|Deng|dever=Cornimont, Fransa}} * {{deng|fr|LL-Q150 (fra)-LoquaxFR-ça.wav|Deng|dever=Vosges, Fransa}} === Cînav === {{cînav|fr}} # [[ev]] #* {{bêmînak|fr}} qzir7n3trxejdnjwx5ps46autbcz8hc hesp 0 5430 6291748 6262046 2026-07-27T23:13:19Z Ghybu 1393 /* Navdêr */ 6291748 wikitext text/x-wiki {{bnr-h|hêsp}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{deng|ku|LL-Q36368 (kur)-Dildadil-hesp.wav|Deng|dever=Amed}} * {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-hesp.wav|Deng|Bidlîs}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|hesp|nêr|alt.çem.yj=h'''ê'''sp}} [[Wêne:Hesp.jpg|thumb|Hespek]] {{navdêr|ku|z=n+}}, {{bilêv|p|nerm}} # {{f|ku|guhandar}} [[dewar|Dewar]]ek e ku [[şibîn|dişibe]] [[ker]]an lê [[mezin]]tir e û bi taybetî bo lê[[siwar]]bûnê tê bikaranîn. #: {{mk|ku|'''Hespê''' [[beza]], '''hespê''' [[rewan]], '''hespê''' [[şehmoz]].}} #: {{mk|ku|Li '''hespî''' / '''hêsp''' [[siwar]] bûn.}} #: {{mk|ku|Ji '''hespî''' / '''hêsp''' [[peya]] bûn.}} #* {{jêder|ku|{{Jêgirtin/Ehmedê Xanî/Mem û Zîn}}|jêgirtin=Dil maye li pencer û şibakan<br />'''Hespê''' xwe dida l' ciyê peyakan<br />Mîr bir ji Memê temamî şeş dest}} #* {{jêder|ku|jêgirtin=Û '''hespêd''' spehî û cins(xwedan nijadên pak) di nêv wan de heyîn. Çar cins(cûre) '''hesp''' heyîn; Kehêl, Hed, Seglawî, Mi'enneg. Nejdî jî peyda dibin, lakin kêm heyîn|{{jêgirtin/Mele Mehmûdê Bayezîdî/Adat û Rusûmatnameê Ekradiye|r=63}}}} #* {{jêder|ku|jêgirtin=Rêwîtiya li ser '''hespê''' ko jî Mûsilê heta Cizîrê hatibû pê, ez ji hev xistibûm; pişta min, stûyê min bûbû mîna minareya mizgefta Nebî Nûh yê qehîm, min nikaribû ew bilivandina.|{{Jêgirtin/Mehmed Uzun/Hawara Dîcleyê 1/2003}}}} #* {{jêder-pirtûk|ku|jêgirtin='''Hespên''' wan rêhevalên wan bûn, ji bo gera dûr baskên wan bûn, şoreta wan bûn, di şeran de ruhxelasên wan bûn, di şênahiyan de, di şahiyan de, di dawetan de navdengiya wan bû. Wexta bỉ çargaviyê diçûn, te digot wekî lingên wan li erdê nakevin.|nivîskar=Eyüp Kiran| sernav=Dewrêşê Evdî Kulîlka Bilbizêk û Rim|cîh=Stenbol|weşanxane={{w|Nûbihar}}|sal=2018|çap=4|rûpel=34|isbn=978-9944-360-95-1}} #* {{jêder-malper|ku|jêgirtin=Dir û yaqût û mirarî <br>Misk û enber jê dibarî <br>'''Hespê''' şahê şehsiwarî, <br>Angeh ez pabûsî bûm.|nivîskar=Siyahpûş|sernav=Dilberek Min Dî Bi Çavan|url=https://www.helbestakurdi.com/helbest/siyahpus--dilberek-min-di-bi-cavan.html|malper=helbestakurdi.com}} ==== Bi alfabeyên din ==== * {{ku-ar|هەسپ}} * {{ku-kr|һәсп}} ==== Formên alternatîv ==== * {{g|ku|esp}} * {{g|ku|hasp}} * {{herwiha|ku|asp||Kurdên Anatoliyaya Navîn}} ==== Hevmane ==== * {{g|ku|bergîl}} ==== Hespên mê ==== * {{g|ku|mahîn}} * {{g|ku|mehîn}} ==== Jornav ==== * {{g|ku|heywan}} * {{g|ku|simdar}} * {{g|ku|dewar}} ==== Jêrnav ==== {{kol3|ku |[[balad]], [[balade]]<t:hespê ku bilez dibeze> |[[bare]], [[baregî]]<t:hespê [[barhilgir]]> |berzîn<t:hespê 3-salî> |boze<t:hespê [[nêle]]> |cerde<t:hespê [[dureg]]> |çerme<t:hespê [[spî]]> |dêze<t:hespê [[reş]]> |exte<t:hespê [[xesandî]]> |semed<t:hespê [[zer]]> |tosin<t:hespê [[serkêş]]> |xakisterî |xing<t:hespê boz> |kûmêt<t:hespê sor> |şê |Heşînbor<t:hespê Heşînbor> |qedene<t:hespê girs> }} * '''Çavkanî''': Mela Xelîl Mişextî: ''Ferhenga Merg û Jî'', Aras, Hewlêr 2006 ==== Binêre herwiha ==== {{kol3|ku |hêstir |ker |qantir }} {{kol3|ku|sernav=Pêdiviyên hespan |hefsar |kurtan |nal |rikêb |sercil |zîn |perzîn |berzîn |dizgîn |qamût |dox |rext |zengî |cihor }} {{kol3|ku|sernav=Cinsên Hespan |çetilbêlix |hed |hemdanî |kihêl |mehnegî |mi'enneg |nejdî |rîşê |[[seklawî]] / [[seqlawî]] |sêlotê |simrî }} {{kol3|ku|sernav=Navên hespan di destanên kurdî de |Hedban<crz:Dewreşê Evdê> |Borê Qer<crz:Mem û Zîn> |Sosik<crz:Kerr û Kulik> |Nijdî<crz:Kerr û Kulik> |Bilêcan<crz:Kerr û Kulik> }} ==== Navê zanistî ==== * {{q|navz|Equus caballus}} ==== Etîmolojî ==== {{etymon|ku|id=dewarê siwarbûnê|inh|ira-pro>*Hácwah>hesp|text=++|tree=1}} [[hevreh|Hevreh]]a {{hv|ckb|ئەسپ‎|tr=esp}}, [[kurdiya başûrî]] {{q|sdh|sc=Latn|esp}}, goranî/hewramî {{q|hac|sc=Latn|esp}}, gîlekî {{g|glk|اسپ|tr=esp}}, mazenderanî {{g|mzn|اسو‎|tr=esv}}, farisî berê {{g|fa|اسپ‎|tr=esp}} û niha {{g|fa|اسب|tr=esb}}, tacikî {{g|tg|асп}}, [[osetî]] {{g|os|ефс|tr=efs}}, [[peştûyî]] {{g|ps|اسپه|tr=espe|w=[[mahîn]]}} û {{g|ps|اس|tr=es}} / {{g|ps|آس|tr=‎as|w=hesp}}, baxterî {{g|xbc|ασπο|tr=aspo|ts=asp}}, sogdî {{g|sog|𐼰𐼼𐼾𐼷‎|tr=ʾspy|ts=əspí}}, avestayî {{g|ae|𐬀𐬯𐬞𐬀|tr=aspa|ts=espe}}, hexamenişî {{g|peo|𐎠𐎿|tr=a-s|ts=asa}} û {{g|peo|𐎠𐎿𐎱|tr=a-s-p|ts=aspa}}... {{hv|sa|अश्व|tr=áśva}}... lîtwanî {{q|lt|ašva}}... latînî {{q|la|equa|w=[[mahîn]]}} û {{q|la|equus|tr=hesp}}... hîtîtî {{g|hit|𒀲𒆳𒊏𒍑|tr=ekkus}}... yûnaniya mikenî {{g|gmy|𐀂𐀦|ts=íkkʷos}}, {{hv|grc|ἵππος|tr=híppos}}, yûnaniya niha {{g|grc|ίππος|tr=íppos}}... {{hv|hy|էշ|tr=ēš|w=[[ker]]}}. Ji heman rehî herwiha: {{q|ku|siwar}}. Peydabûna ''hesp'' ya kurmancî ji [[proto-hindûewropî]] {{q|ine-pro|*h₁éḱwos}} wiha bûye: ''hesp'' < ''*ʰesp'' < ''*ʰespe'' < *''ʰesve'' < ''ʰeçve'' < ''ʰeçwe'' < *''ʰeçweh'' < *''ʰeçwes'' < {{q|ine-pro|*h₁éḱwos}}. ʰ ya [[jornivîs]] nîşana wê yekê ye ku belkî H li destpêka peyvê hebû yan jî tine bû. Bo guherîna *k ya proto-hindûewropî bi S di zimanên îranî de, bidin ber bo nimûne ''[[ser]]'' û ''[[sed]]''. Bo guherîna *w ya proto-hindûewropî bi P, bidin ber bo nimûne ''[[spî]]''. Peyv ji mêj ve ji zimanên îranî û hindûîranî ketiye gelek zimanan. Bo nimûne akadî {{g|akk|𒊍𒉺𒀪|tr=as-pa-ʾ}}, hurî {{g|xhu|𒀸𒋗𒉿|tr=aš-šu-wa}}, piraniya zimanên Kafkasyayê ''[[*ʼɨčʷe]]''. Peyv ji kurdî (ihtimalen kurmancî) wek {{g|xcl|հասբ|tr=hasb}} ketibû ermeniya kevn jî. Hêjayî gotinê ye ku ''hesp'' ne hevreha peyvên germenî yên bo nimûne wek îngilîzî {{q|en|horse}}, danmarkî {{q|da|hest}} yan swêdî {{q|sv|häst}} e. Ev ji proto-hindûewropî {{q|ine-pro|*ḱr̥sós}} in. ;{{biçûk|Çavkanî * {{Cathcart}} * {{Chyet}} * {{Lubotsky}} * {{Mayrhofer}} * {{Kloekhorst}} * {{Rastorgujeva}} * {{The Tower of Babel}} * {{Tsabolov}} * {{Witzel}} }} ==== Dûnde ==== * {{dû|xcl|հասբ|deyn=1}} ==== Bi zaravayên din ==== * {{Z|ckb}}: {{W-|ckb|ئەسپ|tr=[[esp]]}} * {{Z|sdh}}: {{W-|sdh|esp|sc=Latn}} * {{Z|lki}}: {{W-|lki|esp|sc=Latn}} * {{Z|hac}}: {{W-|hac|esp|sc=Latn}} * {{Z|zza}}: {{W-|zza|estor|n}}, {{W-|zza|îstor|n}} ==== Werger ==== {{werger-ser}} * {{Z|ab}}: {{W-|ab|аҽы}} * {{Z|ace}}: {{W-|ace|guda}} * {{Z|ady}}: {{W-|ady|шы}} * {{Z|aa}}: {{W-|aa|faras}} * {{Z|af}}: {{W+|af|perd}} * {{Z|akz}}: {{W-|akz|chichoba}} * {{Z|sq}}: {{W+|sq|kalë|n}} * {{Z|de}}: {{W+|de|Pferd|nt}}, {{W+|de|Ross|nt}}, {{W+|de|Roß|nt}}, {{W+|de|Gaul|n}}, {{W+|de|Hengst|n}}, {{W-|de|Pferdehengst|n}}, {{W+|de|Stute|m}}, {{W-|de|Pferdestute|m}}, {{W-|de|Hengstfohlen|nt}}, {{W-|de|Hengstfüllen|nt}}, {{W-|de|Stutenfohlen|nt}}, {{W-|de|Stutfohlen|nt}}, {{W-|de|Stutenfüllen|nt}}, {{W-|de|Stutfüllen|nt}}, {{W-|de|Rössel|nt}}, {{W-|de|Rössl|nt}}, {{W-|de|Rössle|nt}} *: {{Z|gsw}}: {{W-|gsw|Ross|nt}} *: {{Z|bar}}: {{W-|bar|Roß|nt}} *: {{Z|pdc}}: {{W-|pdc|Gaul|n}} * {{Z|am}}: {{W+|am|ፈረስ|sc=Ethi}} * Apaçî: *: {{Z|apm}}: {{W-|apm|chelee}} *: {{Z|apj}}: {{W-|apj|chelee}} *: {{Z|apw}}: {{W-|apw|łį́į́ʼ}}, {{W-|apw|chelee}} *: {{Z|apl}}: {{W-|apl|chelee}} *: {{Z|apk}}: {{W-|apk|chelee}} * {{Z|amu}}: {{W-|amu|kísò}} * {{Z|apy}}: {{W-|apy|kawaru}} * {{Z|an}}: {{W-|an|caballo|n}} * {{Z|arc}}: *: {{Z|aii}}: {{W-|aii|ܣܘܼܣܵܐ|tr=susa|n}}, {{W-|aii|ܣܘܼܣܬܵܐ|tr=susta|m}} *: Îbranî: {{W-|arc|סוסיא|n|tr=sūsyā’|sc=Hebr}} *: Siryanî: {{W-|arc|ܣܘܣܝܐ|n|tr=sūsyā’|sc=Syrc}} * {{Z|rup}}: {{W+|rup|cal|n}} * {{Z|aer}}: {{W-|aer|nanthe}} * {{Z|as}}: {{W-|as|ঘোঁৰা|g}} * {{Z|ast}}: {{W+|ast|caballu|n}}, {{W+|ast|burru}} * {{Z|av}}: {{W-|av|чу|sc=Cyrl}} * {{Z|ay}}: {{W-|ay|kawallu}} * {{Z|ain}}: {{W-|ain|ウンマ|tr=umma}} * {{Z|az}}: {{W+|az|at}} *: {{Z|az}}: {{W-|az|آت|tr=at|sc=Arab}} *: Latînî: {{W+|az|at}} * {{Z|drl}}: {{W-|drl|kaangkaru}} * {{Z|bm}}: {{W-|bm|so}} * {{Z|bdy}}: {{W-|bdy|yaramaŋ}}, {{W-|bdy|yaraman}} * {{Z|bjn}}: {{W-|bjn|kuda}} * {{Z|eu}}: {{W+|eu|zaldi}} * {{Z|ba}}: {{W-|ba|ат|sc=Cyrl}}, {{W-|ba|йылҡы|sc=Cyrl}} * {{Z|bbl}}: {{W-|bbl|დოჼ}} * {{Z|sne}}: {{W-|sne|kuda}} * {{Z|bfs}}: {{W-|bfs|maix}} * {{Z|be}}: {{W-|be|конь|n}} * {{Z|bal}}: {{W-|bal|اسپ|tr=asp}}, {{W-|bal|اپس|tr=aps}} * {{Z|bn}}: {{W+|bn|ঘোড়া|sc=Beng}} * {{Z|br}}: {{W+|br|marc'h|n}} * {{Z|kxd}}: {{W-|kxd|kuda}} * {{Z|bg}}: {{W+|bg|кон|n}} * {{Z|my}}: {{W+|my|မြင်း|sc=Mymr}} * {{Z|bua}}: {{W-|bua|адуу}} * {{Z|pcc}}: {{W-|pcc|duezmax}}, {{W-|pcc|max}} * {{Z|chl}}: {{W-|chl|kaváayu}} * {{Z|kac}}: {{W-|kac|gumra}}, {{W-|kac|gumrang}} * {{Z|dz}}: {{W-|dz|རྟ}} * {{Z|ccc}}: {{W-|ccc|kawali}} * {{Z|ce}}: {{W-|ce|говр}}, {{W-|ce|айгІар|n}}, {{W-|ce|кхела|m}} * {{Z|cs}}: {{W+|cs|kůň}} * {{Z|chr}}: {{W-|chr|ᏐᏈᎵ|ts=so²³gwi³li}} * {{Z|chy}}: {{W-|chy|mo'éhno'ha}} * {{Z|ny}}: {{W-|ny|hatchi}}, {{W-|ny|kavalo}} * {{Z|cic}}: {{W-|cic|issoba}}, {{W-|cic|soba}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|馬|tr=maa5}} *: {{Z|dng}}: {{W-|dng|ма}} *: {{Z|gan}}: {{W-|gan|馬|tr=ma3}} *: {{Z|hak}}: {{W-|hak|馬|tr=mâ}} *: {{Z|cjy}}: {{W-|cjy|馬|tr=ma2}} *: {{Z|cmn}}: {{W+|cmn|馬|tr=mǎ}} *: {{Z|mnp}}: {{W-|mnp|馬|tr=mǎ}} *: {{Z|cdo}}: {{W-|cdo|馬|tr=mā}} *: {{Z|nan}}: {{W+|nan|馬|tr=bé}} *: {{Z|wuu}}: {{W-|wuu|馬}} *: {{Z|hsn}}: {{W-|hsn|馬|tr=ma3}} * {{Z|cho}}: {{W-|cho|issuba}} * {{Z|ctu}}: {{W-|ctu|cawayuʼ}} * {{Z|ckt}}: {{W-|ckt|конэкон|tr=konėkon}}, {{W-|ckt|конэт|p|tr=konėt}}, {{W-|ckt|ӈавконэкон|m|tr=ṇavkonėkon}}, {{W-|ckt|ӈавконэт|m-p|tr=ṇavkonėt}} * {{Z|cv}}: {{W-|cv|лаша|sc=Cyrl}} * {{Z|chk}}: {{W-|chk|arus}} * {{Z|dlm}}: {{W-|dlm|cavul|n}} * {{Z|da}}: {{W+|da|hest|g}}, {{W+|da|hingst|g}}, {{W+|da|hoppe}} * {{Z|xdk}}: {{W-|xdk|wanyuwa}} * {{Z|dif}}: {{W-|dif|nhantu}} * {{Z|dv}}: {{W-|dv|އަސް|sc=Thaa}} * {{Z|dgr}}: {{W-|dgr|tłı̨cho}} * {{Z|dlg}}: {{W-|dlg|ат}} * {{Z|duu}}: {{W-|duu|mvgeu}}, {{W-|duu|ta}} * {{Z|ovd}}: {{W-|ovd|est|n}} * {{Z|egl}}: {{W-|egl|cavàl|n}} * {{Z|id}}: {{W+|id|kuda}} * {{Z|ar}}: {{W+|ar|حِصَان|n}}, {{W-|ar|فَرَس|n|m}}, {{W+|ar|خَيْل|m}} *: {{Z|arz}}: {{W-|arz|خيل|n|tr=ḵēl}}, {{W-|arz|حيلة|m|tr=ḵēla}} *: {{Z|afb}}: {{W-|afb|حْصَان|tr=ḥṣān}} *: {{Z|acw}}: {{W-|acw|حُصَان|n|tr=ḥuṣān}}, {{W-|acw|خيل|n|tr=ḵēl}} *: {{Z|ary}}: {{W-|ary|عود|tr=ʿawd}}, {{W-|ary|حصان|tr=ḥiṣān}}, {{W-|ary|خيل|tr=ḵīl}} *: {{Z|ajp}}: {{W-|ajp|حْصَان|tr=ḥṣān}} *: {{Z|ajp}}: {{W-|ajp|حْصَان|tr=ḥṣān}} * {{Z|hy}}: {{W+|hy|ձի}}, {{W+|hy|նժույգ}}, {{W+|hy|երիվար}} * {{Z|myv}}: {{W-|myv|лишме}}, {{W-|myv|алаша}} * {{Z|eo}}: {{W+|eo|ĉevalo}} * {{Z|et}}: {{W+|et|hobune}}, {{W-|et|hobu}} * {{Z|gez}}: {{W-|gez|ፈረስ}} * {{Z|eve}}: {{W-|eve|му̣ри̣н}} * {{Z|evn}}: {{W-|evn|мурин}} * {{Z|ee}}: {{W-|ee|sɔ|nt}} * {{Z|peo}}: {{W-|peo|𐎠𐎿𐎱|ts=aspa}}, {{W-|peo|𐎠𐎿|ts=asa}} * {{Z|fa}}: *: Klasîk: {{W+|fa|اسپ|tr=asp}} *: {{Z|fa}}: {{W+|fa|اسپ|tr=asp}} *: {{Z|fa}}: {{W+|fa|اسب|tr=asb}} * {{Z|phn}}: {{W-|phn|𐤎𐤎|n|ts=sys|sc=Phnx}} * {{Z|fo}}: {{W+|fo|hestur}}, {{W-|fo|ross}} * {{Z|hif}}: {{W-|hif|ghorra}} * {{Z|fj}}: {{W+|fj|ose}} * {{Z|fi}}: {{W+|fi|hevonen}}, {{W+|fi|heppa}}, {{W+|fi|kopukka}}, {{W+|fi|luuska}}, {{W+|fi|polle}}, {{W+|fi|hepo}}, {{W+|fi|humma}}, {{W-|fi|karva-Opel}}, {{W+|fi|koni}}, {{W+|fi|kaakki}}, {{W+|fi|ravuri}}, {{W+|fi|ratsu}}, {{W+|fi|ruuna}}, {{W+|fi|ori}}, {{W+|fi|tamma}} * {{Z|frp}}: {{W-|frp|cheval|n}} * {{Z|fr}}: {{W+|fr|cheval|n}}, {{W+|fr|étalon|n}}, {{W+|fr|jument|m}}, {{W+|fr|poulain|n}}, {{W+|fr|pouliche|m}} *: {{Z|frm}}: {{W-|frm|cheval}} *: {{Z|fro}}: {{W-|fro|cheval}} * {{Z|fur}}: {{W-|fur|cjaval|n}}, {{W-|fur|čhaval|n}} * {{Z|frr}}: {{W-|frr|hingst|n}}, {{W-|frr|Hingst}} * {{Z|stq}}: {{W-|stq|Hoangst|n}} * {{Z|fy}}: {{W-|fy|hynder|nt}}, {{W-|fy|hoppe}}, {{W-|fy|happe}}, {{W-|fy|hoars|nt}} * {{Z|ff}}: {{W-|ff|puccu}} * {{Z|fud}}: {{W-|fud|ōsi}} * {{Z|gd}}: {{W-|gd|each|n}} * {{Z|gag}}: {{W-|gag|beygir}} * {{Z|gl}}: {{W+|gl|cabalo|n}}, {{W+|gl|egua|m}}, {{W-|gl|egoa|m}}, {{W+|gl|besta|m}}, {{W-|gl|faco|n}}, {{W-|gl|griñón|n}}, {{W-|gl|cartao|n}}, {{W+|gl|barrufeiro|n}} * {{Z|roa-gal}}: {{W-|roa-gal|ch'fa|n}} * {{Z|sdn}}: {{W-|sdn|cabaddu|n}}, {{W-|sdn|caddu|n}}, {{W-|sdn|acchettu|n}}, {{W-|sdn|ebba|m}} * {{Z|kld}}: {{W-|kld|yarraaman}} * {{Z|cab}}: {{W-|cab|xuval}} * {{Z|cel-gau}}: {{W-|cel-gau|caballos}} * {{Z|gni}}: {{W-|gni|dimana}}, {{W-|gni|yawarda}} * {{Z|gor}}: {{W-|gor|wadala}} * {{Z|gu}}: {{W+|gu|ઘોડો|n}} * {{Z|ka}}: {{W+|ka|ცხენი|sc=Geor}}, {{W+|ka|ჰუნე|sc=Geor}} * {{Z|kky}}: {{W-|kky|yarraman}}, {{W-|kky|guguur}} * {{Z|gn}}: {{W-|gn|kavaju}} * {{Z|ht}}: {{W-|ht|chwal}} * {{Z|haw}}: {{W-|haw|lio}} * {{Z|ha}}: {{W+|ha|doki}} * {{Z|hac}}: {{W-|hac|ئەسپ|sc=fa-Arab}} * {{Z|mba}}: {{W-|mba|kabayo}} * {{Z|hi}}: {{W+|hi|घोड़ा|n|sc=Deva}}, {{W+|hi|अश्व|n}}, {{W+|hi|तुरग|n|sc=Deva}} * {{Z|hil}}: {{W-|hil|kabayo}} * {{Z|hit}}: {{W-|hit|𒀲𒆳𒊏𒍑|tr=ekkus}} * {{Z|mww}}: {{W-|mww|nees}} * {{Z|nl}}: {{W+|nl|paard|nt}}, {{W+|nl|ros|nt}} * {{Z|hop}}: {{W-|hop|kawayo}} * {{Z|hrx}}: {{W-|hrx|Gaul|n}}, {{W-|hrx|kaul}} * {{Z|he}}: {{W-|he|סוּס|n|tr=sus}} * {{Z|io}}: {{W+|io|kavalo}} * {{Z|ilo}}: {{W-|ilo|kabalio}} * {{Z|ang}}: {{W-|ang|hors|nt}} * {{Z|en}}: {{W+|en|horse}} * {{Z|inh}}: {{W-|inh|ды}}, {{W-|inh|говр}} * {{Z|ia}}: {{W-|ia|cavallo|n}} * {{Z|ik}}: {{W-|ik|tuttuqpak}} * {{Z|ga}}: {{W+|ga|capall|n}}, {{W-|ga|each|n}} *: {{Z|sga}}: {{W-|sga|capall|n}}, {{W-|sga|ech|n}} * {{Z|zai}}: {{W-|zai|maniʼ}} * {{Z|ist}}: {{W-|ist|caval}} * {{Z|ruo}}: {{W-|ruo|co|n}} * {{Z|it}}: {{W+|it|cavallo|n}} * {{Z|ium}}: {{W-|ium|maaz}} * {{Z|is}}: {{W+|is|hestur|n}} * {{Z|ja}}: {{W+|ja|馬|tr=うま, uma}}, {{W+|ja|ウマ|tr=uma}} * {{Z|jv}}: {{W+|jv|jaran}}, {{W-|jv|kapal}}, {{W+|jv|titihan}}, {{W+|jv|kuda}}, {{W+|jv|turangga}} * {{Z|juc}}: {{W-|juc|muri}} * {{Z|kbd}}: {{W-|kbd|шы}} * {{Z|tbd}}: {{W-|tbd|wos}} * {{Z|kl}}: {{W+|kl|hiisti}} * {{Z|xal}}: {{W-|xal|мөрн}} * {{Z|kn}}: {{W+|kn|ಕುದುರೆ}} * {{Z|pam}}: {{W-|pam|kabayu}} * {{Z|xqa}}: {{W-|xqa|اَتْ|tr=at}} * {{Z|krl}}: {{W-|krl|hebo}} * {{Z|ktn}}: {{W-|ktn|ʼiriwity}} * {{Z|csb}}: {{W+|csb|kóń|n}} * {{Z|ca}}: {{W+|ca|cavall|n}} * {{Z|zku}}: {{W-|zku|pindi nanto}} * {{Z|kgp}}: {{W-|kgp|kãvãru}} * {{Z|qu}}: {{W-|qu|kawallu}} * {{Z|ks}}: {{W+|ks|گُر|n}} * {{Z|ket}}: {{W-|ket|көнь}} * {{Z|kjj}}: {{W-|kjj|пши}} * {{Z|ky}}: {{W+|ky|ат|sc=Cyrl}}, {{W+|ky|жылкы|sc=Cyrl}} * {{Z|si}}: {{W-|si|අශ්වය|sc=Sinh}} * {{Z|rw}}: {{W-|rw|ifarashi|c5|c6}} * {{Z|com}}: {{W-|com|puuku}} * {{Z|kok}}: {{W-|kok|tokli}} * {{Z|ko}}: {{W+|ko|말}} * {{Z|kw}}: {{W+|kw|margh|n}} * {{Z|co}}: {{W+|co|cavaddu|n}}, {{W+|co|cavallu|n}} * {{Z|mfe}}: {{W-|mfe|seval}} * {{Z|crs}}: {{W-|crs|seval}} * {{Z|rop}}: {{W-|rop|os}}, {{W-|rop|yarraman}}, {{W-|rop|yawarda}} * {{Z|cr}}: {{W-|cr|ᑳᐸᓚᑲᔅᑴᐤ}}, {{W-|cr|ᒥᐢᑕᑎᒼ}} * {{Z|mus}}: {{W-|mus|rakko}} * {{Z|cuk}}: {{W-|cuk|moli}} * {{Z|kj}}: {{W-|kj|onghambe}} * {{Z|lbj}}: {{W-|lbj|རྟ}} * {{Z|lld}}: {{W-|lld|ciaval}} * {{Z|lad}}: {{W-|lad|kavayo|n}} * {{Z|lbe}}: {{W-|lbe|чву}} * {{Z|lkt}}: {{W-|lkt|tȟašúŋke}}, {{W-|lkt|šúŋkawakȟáŋ}} * {{Z|ltg}}: {{W-|ltg|zyrgs|n}} * {{Z|la}}: {{W+|la|equus|n}}, {{W+|la|caballus|n}} * {{Z|lv}}: {{W+|lv|zirgs|n}} * {{Z|lo}}: {{W-|lo|ມ້າ}} * {{Z|lzz}}: {{W-|lzz|ცხენი}} * {{Z|lez}}: {{W-|lez|шив}} * {{Z|lij}}: {{W-|lij|cavallo|n}} * {{Z|li}}: {{W+|li|paerd|nt}} * {{Z|lt}}: {{W+|lt|arklys|n}}, {{W+|lt|žirgas|n}} * {{Z|liv}}: {{W-|liv|ibbi}}, {{W-|liv|õbbi}} * {{Z|lmo}}: {{W-|lmo|cavall}}, {{W-|lmo|càal}} * {{Z|khb}}: {{W-|khb|ᦙᦱᧉ|sc=Talu}} * {{Z|lg}}: {{W-|lg|embalaasi}} * {{Z|luy}}: {{W-|luy|efarasi}} * {{Z|lb}}: {{W+|lb|Päerd|nt}} * {{Z|mdh}}: {{W-|mdh|kuda}} * {{Z|mk}}: {{W-|mk|коњ|n}} * {{Z|mg}}: {{W+|mg|soavaly}}, {{W-|mg|farasy}} * {{Z|ml}}: {{W+|ml|കുതിര|sc=Mlym}} * {{Z|pqm}}: {{W-|pqm|ahahs|an}} * {{Z|ms}}: {{W+|ms|kuda}} * {{Z|mt}}: {{W-|mt|żiemel|n}} * {{Z|mnc}}: {{W-|mnc|ᠮᠣᡵᡳᠨ}} * {{Z|gv}}: {{W+|gv|cabbyl|n}} * {{Z|msk}}: {{W-|msk|kabayo}} * {{Z|mi}}: {{W-|mi|hōiho}}, {{W-|mi|kamia}} * {{Z|arn}}: {{W-|arn|kawej}} * {{Z|mrw}}: {{W-|mrw|koda'}} * {{Z|mr}}: {{W+|mr|घोडा|sc=Deva}} * Marî: *: {{Z|mhr}}: {{W-|mhr|имне}} *: {{Z|mrj}}: {{W-|mrj|имни}} * {{Z|mrc}}: {{W-|mrc|qwayu}}, {{W-|mrc|qwaqt}} * Marquesan: *: {{Z|mrq}}: {{W-|mrq|puaka piki ènana}}, {{W-|mrq|ekeuna}}, {{W-|mrq|ihovare}}, {{W-|mrq|hovare}}; {{W-|mrq|puaka piki kenana}} *: {{Z|mqm}}: {{W-|mqm|puaa pii ènata}}, {{W-|mqm|eʻeuna}}, {{W-|mqm|sovare}}, {{W-|mqm|soare}} * {{Z|vma}}: {{W-|vma|nyingkurluwinparri}} * {{Z|mzn}}: {{W-|mzn|اسو|tr=asv|sc=mzn-Arab}} * {{Z|gun}}: {{W-|gun|kavaju}} * {{Z|hu}}: {{W+|hu|ló}} * {{Z|xmf}}: {{W-|xmf|ცხენი}} * {{Z|mel}}: {{W-|mel|kudak}} * {{Z|egy}}: {{W-egy|ssm|n|h=z:z-m-E6}}, {{W-egy|ssmt|m|h=s-s-m-t-E6}} * {{Z|lmw}}: {{W-|lmw|kawáj}} * {{Z|mpm}}: {{W-|mpm|kuayu}} * {{Z|xta}}: {{W-|xta|kuái̱}} * {{Z|mvi}}: {{W-|mvi|ヌーマ|tr=nūma}} * {{Z|mic}}: {{W-|mic|te'sipow}} * {{Z|min}}: {{W-|min|kudo}} * {{Z|mdf}}: {{W-|mdf|алаша}}, {{W-|mdf|лишме}} * {{Z|mn}}: {{W+|mn|адуу|sc=Cyrl}}, {{W+|mn|морь}} * {{Z|mnw}}: {{W-|mnw|ချေံ|tr=cheh|sc=Mymr}} * {{Z|mwf}}: {{W-|mwf|nintu}} * {{Z|nci}}: {{W-|nci|cahuayo}}, {{W-|nci|cahuāllo}} * {{Z|nhx}}: {{W-|nhx|cahua̱yoj}} * {{Z|nah}}: {{W+|nah|cahuāyoh}} * {{Z|naq}}: {{W-|naq|hab}} * {{Z|gld}}: {{W-|gld|морин}} * Nanticoke: *: {{Z|psy}}: {{W-|psy|misatimwa}} * {{Z|nv}}: {{W-|nv|łį́į́ʼ}} * {{Z|ng}}: {{W-|ng|okakambe}} * {{Z|nds}}: *: {{Z|nds-nl}}: {{W-|nds-nl|peerd|nt}}, {{W-|nds-nl|peard|nt}} *: {{Z|nds-de}}: {{W-|nds-de|Peerd|nt}}, {{W-|nds-de|Peer|nt}} * {{Z|neg}}: {{W-|neg|моји̣н}} * {{Z|ne}}: {{W+|ne|घोडा}} * {{Z|wyb}}: {{W-|wyb|yarraaman}} * {{Z|niv}}: {{W-|niv|мурӈ}}, {{W-|niv|мур̌}} * {{Z|nrf}}: {{W-|nrf|j'va|n}}, {{W-|nrf|ch'fa|n}}, {{W-|nrf|queva|n}} * {{Z|no}}: {{W+|no|hest|n}} * {{Z|nys}}: {{W-|nys|ngort}} * {{Z|ood}}: {{W-|ood|kaviyu}}, {{W-|ood|kawiyu}} * {{Z|oj}}: {{W-|oj|ᐯᐯᔑᑰᑲᓐᔒ|tr=bebezhigooganzhii}} * {{Z|oc}}: {{W+|oc|caval|n}}, {{W+|oc|èga|m}} * {{Z|or}}: {{W+|or|ଘୋଡ଼ା}} * {{Z|oac}}: {{W-|oac|мури}} * {{Z|oaa}}: {{W-|oaa|му̣ри̣}} * {{Z|om}}: {{W+|om|farda}} * {{Z|orh}}: {{W-|orh|mʊrɪn}} * {{Z|os}}: {{W-|os|бӕх}} * {{Z|ota}}: {{W-|ota|آت}} * {{Z|ug}}: {{W+|ug|ئات|sc=ug-Arab}} * {{Z|uz}}: {{W+|uz|ot}} * {{Z|pac}}: {{W-|pac|axéh}} * {{Z|pau}}: {{W-|pau|uos}} * {{Z|pi}}: {{W-|pi|assa}} * {{Z|pap}}: {{W-|pap|kabai}} * {{Z|ps}}: {{W+|ps|آس|n|tr=ās|sc=ps-Arab}} * {{Z|pms}}: {{W-|pms|caval|n}} * {{Z|pcd}}: {{W-|pcd|kvau|n}} * {{Z|ppl}}: {{W-|ppl|kawayu}} * {{Z|pdt}}: {{W-|pdt|Pieet|nt}} * {{Z|pox}}: {{W-|pox|ťün|n}} * {{Z|pl}}: {{W+|pl|koń|n}}, {{W+|pl|klacz|m}} * {{Z|pos}}: {{W-|pos|cawa̱yu}} * {{Z|pt}}: {{W+|pt|cavalo|n}}, {{W+|pt|égua|m}} * {{Z|pa}}: {{W+|pa|ਘੋੜਾ|n}} * {{Z|kk}}: {{W-|kk|жылқы|sc=Cyrl}}, {{W+|kk|ат|sc=Cyrl}} * {{Z|cop}}: {{W-|cop|ϩⲧⲟ}} * {{Z|rhg}}: {{W-|rhg|gúra}} * {{Z|rgn}}: {{W-|rgn|cavàl|n}} * {{Z|rm}}: {{W-|rm|chaval|n}} * {{Z|rom}}: {{W-|rom|grast|n}}, {{W-|rom|grasni|m}} * {{Z|ro}}: {{W+|ro|cal}} * {{Z|ru}}: {{W-|ru|ло́шадь|m}}, {{W+|ru|конь|n}} * {{Z|rue}}: {{W-|rue|кінь|n}} * {{Z|ksw}}: {{W-|ksw|ကသ့ၣ်}} * {{Z|slr}}: {{W-|slr|ate}} * Samî: *: {{Z|sjd}}: {{W-|sjd|е̄бешь}} * {{Z|se}}: {{W-|se|heasta}} * {{Z|sms}}: {{W-|sms|heävaš}} * {{Z|sm}}: {{W-|sm|solofanua}} * {{Z|sgs}}: {{W-|sgs|arklīs|n}} * {{Z|smq}}: {{W-|smq|hosi}} * {{Z|sg}}: {{W+|sg|mbârâtâ}} * {{Z|sa}}: {{W+|sa|अश्व|n}}, {{W+|sa|घोटक|n}}, {{W+|sa|तुरग|n}}, {{W+|sa|अर्वन्|n}}, {{W+|sa|हय|n}}, {{W+|sa|वातायन|n}} * {{Z|sat}}: {{W-|sat|ᱥᱚᱫᱳᱢ|sc=Olck}} * Sardinian: *: {{Z|sc}}: {{W-|sc|cuaddu|n}}, {{W-|sc|egua|m}} * {{Z|sdc}}: {{W-|sdc|cabaddu|n}}, {{W-|sdc|caddu|n}}, {{W-|sdc|acchettu|n}}, {{W-|sdc|ebba|m}} * {{Z|ceb}}: {{W-|ceb|kabayo}} * {{Z|sei}}: {{W-|sei|caay}} * {{Z|scn}}: {{W+|scn|cavaddu|n}} * {{Z|sid}}: {{W-|sid|farado}} * {{Z|szl}}: {{W-|szl|kůń|n}} * {{Z|srn}}: {{W-|srn|asi}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|коњ|n|sc=Cyrl}} *: Latînî: {{W+|sh|konj|n|sc=Latn}} * {{Z|syl}}: {{W-|syl|ꠊꠥꠠꠣ}} * {{Z|sco}}: {{W-|sco|horse}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|конь|n}} *: Glagolîtîk: {{W-|cu|ⰽⱁⱀⱐ|n}} * {{Z|orv}}: {{W-|orv|конь|n}} * {{Z|sk}}: {{W+|sk|kôň|n}} * {{Z|sl}}: {{W+|sl|konj|n}} * {{Z|tuw-sol}}: {{W-|tuw-sol|moring}} * {{Z|so}}: {{W+|so|faras|n}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|kóń|n}} *: {{Z|hsb}}: {{W+|hsb|kóń|n}} * {{Z|st}}: {{W+|st|pere}} * {{Z|es}}: {{W+|es|caballo|n}} * {{Z|su}}: {{W-|su|kuda}} * {{Z|sux}}: {{W-|sux|𒀲|tr=anše}}, {{W-|sux|𒀲𒆳𒊏|tr=sisi}} * {{Z|sva}}: {{W-|sva|ჩა̈̄ჟ}} * {{Z|sw}}: {{W+|sw|farasi}} * {{Z|sv}}: {{W+|sv|häst|g}}, {{W+|sv|russ|g}}, {{W+|sv|fåle|g}} * {{Z|shn}}: {{W-|shn|မႃႉ}} * {{Z|xsr}}: {{W-|xsr|རྟ}} * {{Z|sn}}: {{W-|sn|bhiza}} * {{Z|cjs}}: {{W-|cjs|ат|tr=at|sc=Cyrl}} * {{Z|tab}}: {{W-|tab|гъяйван}} * {{Z|tg}}: {{W+|tg|асп|sc=Cyrl}} * {{Z|tl}}: {{W+|tl|kabayo}} * {{Z|tly}}: {{W-|tly|اسب|tr=asb}} * {{Z|oty}}: {{W-|oty|𑀫𑀸}} * {{Z|ta}}: {{W+|ta|குதிரை}}, {{W+|ta|புரவி|sc=Taml}} * {{Z|twf}}: {{W-|twf|kówena}} * {{Z|rif}}: {{W-|rif|yis|n}} * {{Z|jdt}}: {{W-|jdt|гӀэсб}} * {{Z|tsg}}: {{W-|tsg|kura}} * {{Z|th}}: {{W+|th|ม้า}} * {{Z|tdd}}: {{W-|tdd|ᥛᥣᥳ}} * {{Z|te}}: {{W+|te|గుర్రము}}, {{W+|te|గుర్రం}} * {{Z|crh}}: {{W-|crh|at}} * {{Z|tt}}: {{W+|tt|ат|sc=Cyrl}} * {{Z|tet}}: {{W-|tet|kuda}} * {{Z|ti}}: {{W+|ti|ፈረስ|sc=Ethi}} * {{Z|otk}}: {{W-|otk|𐱃|ts=at}}, {{W-|otk|𐰖𐰆𐰣𐱃|ts=yunt}} * {{Z|tr}}: {{W+|tr|at}}, {{W-|tr|deh deh}}, {{W+|tr|beygir}} * {{Z|tk}}: {{W+|tk|at}} * {{Z|bo}}: {{W-|bo|རྟ}}, {{W-|bo|རྨང|sc=Tibt}} * {{Z|tpi}}: {{W-|tpi|hos}} * {{Z|to}}: {{W-|to|hoosi}} * {{Z|xto}}: {{W-|xto|yuk}} * {{Z|txb}}: {{W-|txb|yakwe}} * {{Z|tn}}: {{W-|tn|pitsi}} * {{Z|tyv}}: {{W-|tyv|аът}}, {{W-|tyv|чылгы}} * {{Z|tzo}}: {{W-|tzo|k'a}} * {{Z|ude}}: {{W-|ude|муи}} * {{Z|udi}}: {{W-|udi|еък|sc=Cyrl}} * {{Z|udm}}: {{W-|udm|вал}} * {{Z|uga}}: {{W-|uga|𐎒𐎒𐎆}} * {{Z|ur}}: {{W-|ur|گھوڑا|n|tr=ghoṛā}} * {{Z|uk}}: {{W+|uk|кінь|n}} * {{Z|vec}}: {{W-|vec|cavało|n}}, {{W-|vec|caval|n}} * {{Z|vi}}: {{W+|vi|ngựa}} * {{Z|vo}}: {{W+|vo|jevod}} * {{Z|vro}}: {{W-|vro|hopõn'}} * {{Z|vot}}: {{W-|vot|opõn}} * {{Z|wls}}: {{W-|wls|hosi}} * {{Z|wa}}: {{W+|wa|tchivå|n}} * {{Z|war}}: {{W-|war|kabayo}} * {{Z|wrr}}: {{W-|wrr|nendo}}, {{W-|wrr|dimana}} * {{Z|xww}}: {{W-|xww|yareman}} * {{Z|cy}}: {{W+|cy|ceffyl|n}} * {{Z|wrh}}: {{W-|wrh|yarraman}} * {{Z|wym}}: {{W-|wym|faod|nt}} * {{Z|wo}}: {{W+|wo|fas|cuda=fas wi}}, {{W+|wo|fas}} * {{Z|kjh}}: {{W-|kjh|ат|sc=Cyrl}} * {{Z|kca}}: {{W-|kca|лʼов}} * {{Z|xav}}: {{W-|xav|awaru}} * {{Z|km}}: {{W+|km|សេះ|tr=seh|sc=Khmr}} * Komi: *: {{Z|koi}}: {{W-|koi|вӧв}} *: {{Z|kpv}}: {{W-|kpv|вӧв}} * {{Z|xh}}: {{W-|xh|ihashe|c5|c6}} * {{Z|yai}}: {{W-|yai|асп}} * {{Z|ybh}}: {{W-|ybh|ओन्‍पा}}, {{W-|ybh|ओन}} * {{Z|sah}}: {{W-|sah|ат}}, {{W-|sah|сылгы}} * {{Z|jao}}: {{W-|jao|yarraman}} * {{Z|yi}}: {{W-|yi|פֿערד|nt}} * {{Z|yij}}: {{W-|yij|yawarda}} * {{Z|ii}}: {{W-|ii|ꃅ}} * {{Z|yo}}: {{W-|yo|ẹṣin}} * {{Z|yuy}}: {{W-|yuy|mörë}} * {{Z|ykg}}: {{W-|ykg|йоходилэ}} * {{Z|el}}: {{W+|el|άλογο|nt}}, {{W+|el|ίππος|n}} *: Kevn: {{W-|grc|ἵππος|n}} *: {{Z|gmy}}: {{W-|gmy|𐀂𐀦}} * {{Z|zav}}: {{W-|zav|cabey}} * {{Z|zpq}}: {{W-|zpq|cabayw}} * {{Z|zea}}: {{W-|zea|paerd|nt}} * {{Z|za}}: {{W-|za|max}} * {{Z|zu}}: {{W+|zu|ihhashi|c5|c6}} {{werger-bin}} :{{werger çavkanî|en|horse|beş=Ev qismê Wergerê|oldid=75656972}} luirkiq4q38pbx0ayt5tsblf8hf3phe dayê 0 6936 6291805 6263518 2026-07-28T03:04:16Z Ghybu 1393 /* {{ziman|ku}} */ Ji gotara [[bacı]] 6291805 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{navdêr|ku|form=erê}} # Peyvek bangkirina li [[dayik]]ê ye. #: '''''Dayê''', [[rebenê]], de bes bigirî...'' ==== Bi alfabeyên din ==== * {{ku-ar|دایێ}} ==== Formên alternatîv ==== * [[daê]] ==== Hevmane ==== * [[yadê]] ==== Etîmolojî ==== : [[day]] = [[yad]] = [[dayik]] ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|ar|إفترش|guman=erê}}, {{W|ar|أكسب|guman=erê}}, {{W|ar|أمد|guman=erê}}, {{W|ar|أملك|guman=erê}}, {{W|ar|أنال|guman=erê}}, {{W|ar|بر|guman=erê}}, {{W|ar|بــص|guman=erê}}, {{W|ar|حثم|guman=erê}}, {{W|ar|خضم|guman=erê}}, {{W|ar|زكأ|guman=erê}}, {{W|ar|عل|guman=erê}}, {{W|ar|قاوى|guman=erê}}, {{W|ar|مانح|guman=erê}}, {{W|ar|مثج|guman=erê}}, {{W|ar|ناله‌|guman=erê}}, {{W|ar|نفح|guman=erê}}, {{W|ar|نول|guman=erê}}, {{W|ar|همر|guman=erê}}, {{W|ar|هنأ|guman=erê}} * {{Z|tr}}: {{W|fr|maman}} * {{Z|en}}: {{W|en|mommy}}, {{W|en|mummy}}, {{W|en|mom}}, {{W|en|mum}}, {{W|en|ma}} * {{Z|tr}}: {{W|tr|ana}} {{werger-bin}} === Navdêr === {{navdêr|ku|z=m}} # Di terîqetan de jina [[şêx]]. #* {{bêmînak|ku}} ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|tr|bacı}} {{werger-bin}} clwx18rkun60qfbsrs11d6qo2doyg2q 6291806 6291805 2026-07-28T03:08:33Z Ghybu 1393 /* Werger */ 6291806 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{navdêr|ku|form=erê}} # Peyvek bangkirina li [[dayik]]ê ye. #: '''''Dayê''', [[rebenê]], de bes bigirî...'' ==== Bi alfabeyên din ==== * {{ku-ar|دایێ}} ==== Formên alternatîv ==== * [[daê]] ==== Hevmane ==== * [[yadê]] ==== Etîmolojî ==== : [[day]] = [[yad]] = [[dayik]] ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|ar|مَامَا|guman=erê}} * {{Z|tr}}: {{W|fr|maman}} * {{Z|en}}: {{W|en|mommy}}, {{W|en|mummy}}, {{W|en|mom}}, {{W|en|mum}}, {{W|en|ma}}, {{W|en|mama}} * {{Z|tr}}: {{W|tr|ana}} {{werger-bin}} === Navdêr === {{navdêr|ku|z=m}} # Di terîqetan de jina [[şêx]]. #* {{bêmînak|ku}} ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|tr|bacı}} {{werger-bin}} aztzv1yh30mylflcpcnah0xmr9peikn 6291807 6291806 2026-07-28T03:14:46Z Ghybu 1393 6291807 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{navdêr|ku|form=erê}} # Peyvek bangkirina li [[dayik]]ê ye. #: {{mk|ku|'''Dayê''', [[rebenê]], de bes bigirî...}} ==== Bi alfabeyên din ==== * {{ku-ar|دایێ}} ==== Formên alternatîv ==== * [[daê]] ==== Hevmane ==== * [[yadê]] ==== Etîmolojî ==== [[day]] = [[yad]] = [[dayik]] ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|ar|مَامَا|guman=erê}} * {{Z|tr}}: {{W|fr|maman}} * {{Z|en}}: {{W|en|mommy}}, {{W|en|mummy}}, {{W|en|mom}}, {{W|en|mum}}, {{W|en|ma}}, {{W|en|mama}} * {{Z|tr}}: {{W|tr|anne}}, {{W|tr|ana}} {{werger-bin}} === Navdêr === {{navdêr|ku|z=m}} # Di terîqetan de jina [[şêx]]. #* {{bêmînak|ku}} ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|tr|ana}}, {{W|tr|bacı}} {{werger-bin}} ihvabyzi30tnsxs8ss0d8wanltiypve 6291808 6291807 2026-07-28T03:18:43Z Ghybu 1393 /* Werger */ 6291808 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{navdêr|ku|form=erê}} # Peyvek bangkirina li [[dayik]]ê ye. #: {{mk|ku|'''Dayê''', [[rebenê]], de bes bigirî...}} ==== Bi alfabeyên din ==== * {{ku-ar|دایێ}} ==== Formên alternatîv ==== * [[daê]] ==== Hevmane ==== * [[yadê]] ==== Etîmolojî ==== [[day]] = [[yad]] = [[dayik]] ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|ar|مَامَا|guman=erê}} * {{Z|tr}}: {{W|fr|maman}} * {{Z|en}}: {{W|en|mommy}}, {{W|en|mummy}}, {{W|en|mom}}, {{W|en|mum}}, {{W|en|ma}}, {{W|en|mama}} * {{Z|tr}}: {{W|tr|anne}}, {{W|tr|ana}} {{werger-bin}} === Navdêr === {{navdêr|ku|z=m}} # Di terîqetan de jina [[şêx]]. #* {{bêmînak|ku}} ==== Werger ==== {{werger-ser}} * {{Z|ar}}: {{W|tr|bacı}} {{werger-bin}} myqsn1qwacejpdh3bp8a0na6wh41wz1 daê 0 6937 6291804 5886442 2026-07-28T02:53:13Z Ghybu 1393 6291804 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{navdêr|ku|form=erê}} # {{guherto|ku|dayê}} 50vsmhwo44wdb5d9xufl2c887mno1u6 bar 0 8402 6291743 6209394 2026-07-27T23:10:39Z Ghybu 1393 /* Navdêr 1 */ 6291743 wikitext text/x-wiki {{bnr-h|Bar|-bar|-bar-}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|bar|nêr|alt.çem.yj=b'''ê'''r}} [[Wêne:A street trader has the panniers on his donkey loaded with v Wellcome V0039673.jpg|thumb|250px|'''Bar''' li pişta kerekî (1).]] {{navdêr|ku|z=n}} # Tişta/ê ku mirovek yan [[dewar]]ek yan [[tirimpêl]]ek [[hilgirtin|hildigire]] û [[raguhastin|radiguhêze]] ([[nemaze]] tiştekî [[giran]]). #: {{mk|ku|'''Bar''' li keran kirin.}} #: {{mk|ku|'''Barê''' li pişta hespî gelek giran bû.}} #: {{mk|ku|Kamyon hat '''bar'''kirin.}} # [[neqil]], [[neqil]]kirin, [[raguhastin]] #: {{mk|ku|Me mala xwe '''bar''' kir.}} #: {{mk|ku|Koçer biharê ji deştê '''bar''' dikin zozanan.}} # [[şarj]], [[şehn]], [[dagirtin]]a [[baterî|bateriyan]] #: {{mk|ku|Dixwazim telefona xwe '''bar''' bikim.}} # {{f|ku|mecazî}} [[berpirsiyarî]], [[mesûliyet]], [[erk]], [[peywir]], [[wacib]], [[wezîfe]], [[vatinî]] #: {{mk|ku|Parastin û pêşxistina zimanê kurdî '''barê''' ser milê her kurdekî ye.}} ==== Ji wêjeya klasîk ==== * {{jêder|ku|jêgirtin="Ma remeyte îz remeyte" goşîdar<br />Destê wî destê Xuda der kar û '''bar'''|Mela Hisênê Bateyî: ''Mewlûd''}} ==== Bi alfabeyên din ==== * {{ku-ar|بار}} * {{ku-kr|бар}} ==== Hevmane ==== * {{mj|barê ku mirov hildigirin}} [[piştî]] (2) * {{mj|barê ku [[tirimpêl]], [[keştî]] yan [[balafir]]an}} [[kargo]] ==== Jê ==== {{kol3|ku|cure=Jê | bargir | bargiran | bargiranî | bargîr | barhilgir | barhilgirî | barker | bar kirin | bar kirin | barkirî | barsivik | barsivikî }} ==== Bide ber ==== {{kol3|ku | ber | bêr | bir | bîr | bor | bûr }} ==== Qafiye ==== {{kol3|ku | ar | car | çar | dar | gar | har | jar | kar | lar | mar | nar | par | sar | şar | tar | war | xar | yar | zar }} ==== Etîmolojî ==== Ji {{ji|ine-pro|ku|*bʰer-|w=[[birin]], [[hilgirtin]], [[rakirin]], [[raguhastin]]}}. Hevreha soranî {{g|ckb|بار}}, [[kurdiya başûrî]] {{q|sdh|bar|sc=Latn}}, goranî/hewramî {{q|hac|bar|sc=Latn}}, zazakî {{q|zza|bar}}, belûçî {{g|bal|بار|tr=bar}}, farisî {{g|fa|بار|tr=bar}}, pehlewî {{q|pal|bʾl|tr=bār}}, tacikî {{g|tg|бор|tr=bor}}, sanskrîtî {{g|sa|भार|tr=bhārá}}, hindî {{g|hi|भार|tr=bhār}}, albanî {{q|sq|barrë}}, ermenî {{g|hy|բեռն|tr=beṙn}}, almanî {{q|de|Bürde}}, îngilîzî {{q|en|burden}} û {{q|en|bear|w=[[hilgirtin]], [[rakirin]]}}, danmarkî {{q|da|byrde}}, swêdî {{q|sv|börda}}, norwecî {{q|no|bør}}, yûnaniya kevn {{q|grc|φόρτος|tr=phórtos}}, rusî {{q|ru|бре́мя|tr=brémya}}, latviyayî {{q|lv|bērns|w=[[zarok]] - ku "barê zikê dayikê" ye}}... Ji eynî rehî herwiha ev peyvên kurdî: * [[birin]] * [[ber]] ([[berhem]], [[fêkî]], [[mêwe]]) ;{{biçûk|Çavkanî: * {{Chyet}} * {{Horn}} * {{Lubotsky}} * {{MacKenzie}} * {{Novák}} * {{Tsabolov}} * {{The Tower of Babel}} }} ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|Bürde|n}}, {{W+|de|Belastung|n}}, {{W+|de|Last|n}}, {{W+|de|Ausschank|nt}}, {{W+|de|Gepäck|nt}}, * {{Z|rup}}: {{W-|rup|sartsinã|m}}, {{W-|rup|greatsã|m}}, {{W-|rup|griutati|m}}, {{W-|rup|furtii|m}}, {{W-|rup|var}} * {{Z|as}}: {{W-|as|বোজা}} * {{Z|bg}}: {{W+|bg|това́р|n}} * {{Z|cs}}: {{W+|cs|břemeno|nt}}, {{W-|cs|zatížení|nt}}, {{W+|cs|náklad|n}}, {{W-|cs|zátěž|m}} * {{Z|zh}}: *: {{Z|cmn}}: {{W+|cmn|負荷|sc=Hani}}, {{W+|cmn|负荷|tr=fùhè|sc=Hani}} * {{Z|da}}: {{W-|da|byrde|c}}, {{W-|da|læs|nt}} * {{Z|ar}}: {{W+|ar|حمل}} (ḧiml), {{W-|ar|عبء}} ('ibi') *: {{arz}}: {{W-|arz|حمل|m|tr=ḥiml}} * {{Z|hy}}: {{W+|hy|բեռ}} * {{Z|fa}}: {{W+|fa|بار}} * {{Z|fo}}: {{W-|fo|byrði|m}}, {{W-|fo|byrða|m}}, {{W-|fo|burður|n}} * {{Z|fi}}: {{W+|fi|kuorma}}, {{W+|fi|taakka}} * {{Z|fr}}: {{W+|fr|charge|m}}, {{W+|fr|fardeau|n}} * {{Z|gl}}: {{W+|gl|carga|m}} *: {{Z|gsw}}: {{W-|gsw|Burdi|m}} * {{Z|nl}}: {{W+|nl|last|n}} * {{Z|he}}: {{W+|he|נטל|m|tr=net'el|sc=Hebr}}, {{W+|he|עֹל|m|tr='ol|sc=Hebr}} * {{Z|en}}: {{W+|en|burden}}, {{W+|en|load}}, {{W+|en|cargo}} * {{Z|ga}}: {{W-|ga|muirear|n}} * {{Z|it}}: {{W+|it|carico|n}}, {{W+|it|fardello}} * {{Z|is}}: {{W+|is|byrði|m}}, {{W+|is|burður|n}} * {{Z|ja}}: {{W+|ja|積み荷|tr=つみに, tsumini|sc=Jpan}} * {{Z|ca}}: {{W+|ca|càrrega|m}}, {{W+|ca|carga}} * {{Z|ko}}: {{W+|ko|짐}}, {{W+|ko|바리}} * {{Z|la}}: {{W-|la|onus|nt}}, {{W-|la|sarcina|m}} * {{Z|ms}}: {{W+|ms|beban}} * {{Z|mi}}: {{W-|mi|wahanga}}, {{W-|mi|wahanga}} * {{Z|hu}}: {{W+|hu|teher}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|byrde|n}}, {{W-|nb|belastning|m|m}} *: {{Z|nn}}: {{W-|nn|byrde|m}}, {{W-|nn|belastning|m}} * {{Z|pl}}: {{W+|pl|ciężar|n}}, {{W+|pl|brzemię|nt}} * {{Z|pt}}: {{W+|pt|carga}}, {{W+|pt|fardo|n}} * {{Z|ro}}: {{W+|ro|sarcină|m}}, {{W+|ro|povară|m}} * {{Z|ru}}: {{W+|ru|но́ша|m}}, {{W+|ru|груз|n}} * {{Z|sa}}: {{W+|sa|भार|n}} * {{Z|sh}}: *: [[krîlî]]: {{W-|sh|бре̏ме|nt}} *: [[latînî]]: {{W+|sh|brȅme|nt}} * {{Z|sk}}: {{W-|sk|bremeno|nt}} * {{Z|es}}: {{W+|es|carga}} * {{Z|sw}}: {{W+|sw|mzigo}} * {{Z|sv}}: {{W+|sv|börda}}, {{W+|sv|belastning}} * {{Z|tl}}: {{W-|tl|dinadalang mabigat}} * {{Z|tr}}: {{W+|tr|yük}} * {{Z|el}}: *: {{Z|grc}}: {{W-|grc|ἄχθος|nt}}, {{W-|grc|φόρημα|nt}} {{werger-bin}} === Navdêr 2 === {{navdêr|ku|z=m}} # [[par]], [[behr]], [[pişk]], [[beş]], [[qism]], [[qismet]] #: {{mk|ku|Bila nîv jê '''bara''' te be û nîv jî '''bara''' min.}} ==== Etîmolojî ==== Binêrin: '''[[par]]''' (2) ==== Werger ==== {{werger-ser}} {{werger-bin}} === Navdêr 3 === {{navdêr|ku|z=m}} # [[car]], [[keret]], [[defe]] #: {{mk|ku|car û '''bar'''an|[[carinan]], [[hinek]] [[car]]an|birêz=1}} #: {{mk|ku|du'''bar'''e|[[ducarî]], [[tekrar]]|birêz=1}} ==== Jê ==== * [[carûcaran]] * [[dubare]] ==== Etîmolojî ==== Hevreha farisî {{g|fa|بار|tr=bar}}, pehlewî ''bar'' ji ''bar'' ya bi wateya "neqil" (li jortir binêrin). Bo guherîna "neqil > car" bidin ber peyva ''[[neqil]]'' ku di hinek devokan de bi wateya "[[car]]" tê bikaranîn. ==== Werger ==== {{werger-ser}} {{werger-bin}} === Navdêr 4 === {{ku-tewîn-nav|bar|mê}} [[Wêne:L'échanson,_Nancy.jpg|thumb|250px|Barek]] {{navdêr|ku|z=m}} # Cihê ku [[alkol]] anku [[meşrûb]] lê tê [[firotin]] û [[vexwarin]]. #* {{bêmînak|ku}} ==== Hevmane ==== * [[badexane]] * [[meyxane]] * [[pûb]] * [[noşînxane]] * [[vexwarinxane]] ==== Etîmolojî ==== Deyn ji {{deyn|en|ku|bar}} li [[nîvek]]a [[duyem]] ya [[sedsal]]a 20em. ==== Werger ==== {{werger-ser}} * {{Z|sq}}: {{W+|sq|bar|n}}, {{W+|sq|pijetore|m}} * {{Z|de}}: {{W+|de|Bar|m}}, {{W+|de|Kneipe|m}}, {{W+|de|Beisl|nt}}, {{W+|de|Lokal|nt}}, {{W+|de|Gasthaus|nt}} * {{Z|az}}: {{W+|az|bar}}, {{W-|az|meyxana}}, {{W-|az|pivəxana}} * {{Z|be}}: {{W-|be|бар|n}}, {{W-|be|піўна́я|m}}, {{W-|be|карчма́|m}}, {{W-|be|тракці́р|n}}, {{W-|be|паб|n}}, {{W-|be|каба́к|m}} * {{Z|bn}}: {{W+|bn|বার}} * {{Z|bg}}: {{W-|bg|бар}}, {{W+|bg|кръ̀чма|m}}, {{W+|bg|пи́вница|m}}, {{W+|bg|механа́|m}} * {{Z|my}}: {{W+|my|ဘား}}, {{W-|my|အရက်ဆိုင်}} * {{Z|cs}}: {{W+|cs|bar|n}}, {{W+|cs|krčma|m}}, {{W+|cs|hospoda|m}}, {{W+|cs|hostinec|n}} * {{Z|ny}}: {{W-|ny|bala}} * {{Z|zh}}: *: {{Z|yue}}: {{W|yue|酒吧|tr=zau2 baa1}} *: {{Z|cmn}}: {{W+|cmn|酒吧|tr=jiǔbā}}, {{W+|cmn|酒館}}, {{W+|cmn|酒馆|tr=jiǔguǎn}}, {{W+|cmn|酒店|tr=jiǔdiàn}} * {{Z|da}}: {{W+|da|bar|c}}, {{W-|da|kro|c}} * {{Z|id}}: {{W+|id|bar}} * {{Z|ar}}: {{W-|ar|خَانَة|m}}, {{W+|ar|بَار|m|tr=bar}} * {{Z|hy}}: {{W+|hy|բար}}, {{W+|hy|պանդոկ}}, {{W+|hy|գինետուն}}, {{W+|hy|փաբ}} * {{Z|eo}}: {{W-|eo|drinkejo}} * {{Z|et}}: {{W+|et|baar}}, {{W+|et|kõrts}}, {{W+|et|trahter}} * {{Z|fa}}: {{W+|fa|بار|tr=bâr}}, {{W+|fa|میخانه|tr=meyxâne}} * {{Z|fo}}: {{W-|fo|ølstova|m}}, {{W-|fo|ølklubbi|n}}, {{W-|fo|barr|m}}, {{W-|fo|krógv|m}}, {{W-|fo|drykkjustova|m}} * {{Z|fi}}: {{W+|fi|baari}}, {{W+|fi|kapakka}}, {{W+|fi|krouvi}}, {{W-|fi|anniskelupaikka}} * {{Z|fr}}: {{W+|fr|bar|n}}, {{W+|fr|pub|n}}, {{W+|fr|taverne|m}} * {{Z|gd}}: {{W-|gd|bàr|n}} * {{Z|ka}}: {{W+|ka|ბარი}}, {{W-|ka|ლუდხანა}} * {{Z|hi}}: {{W+|hi|बार|n}}, {{W-|hi|शराब-घर|n}}, {{W-|hi|पब}} * {{Z|nl}}: {{W+|nl|bar|n}}, {{W+|nl|café|nt}}, {{W+|nl|taveerne|n}}, {{W+|nl|kroeg|m}} * {{Z|he}}: {{W+|he|באר|m|tr=bar|cuda=בָּאר \ בָּר}}, {{W+|he|בָּר|m|tr=bar}} * {{Z|en}}: {{W+|en|bar}}, {{W+|en|pub}} * {{Z|ia}}: {{W-|ia|bar}} * {{Z|ga}}: {{W-|ga|teach leanna|n}}, {{W-|ga|teach tábhairne|n}} * {{Z|it}}: {{W+|it|bar|n}}, {{W+|it|taverna|m}}, {{W+|it|birreria|m}} * {{Z|is}}: {{W+|is|bar|n}}, {{W+|is|krá|m}}, {{W-|is|ölstofa|m}}, {{W-|is|pöbb|n}}, {{W-|is|knæpa|m}} * {{Z|ja}}: {{W-|ja|バー|tr=bā}}, {{W+|ja|居酒屋|tr=いざかや, izakaya}}, {{W-|ja|パブ|tr=pabu}}, {{W+|ja|飲み屋|tr=のみや, nomiya}}, {{W+|ja|酒場|tr=さかば, sakaba}} * {{Z|ky}}: {{W+|ky|бар}}, {{W-|ky|араккана}} * {{Z|ko}}: {{W+|ko|술집}}, {{W+|ko|바}}, {{W-|ko|퍼브}} * {{Z|la}}: {{W-|la|oecus potorius]]|n}}, {{W+|la|taberna|m}} * {{Z|la}}: {{W-|lv|bārs|n}}, {{W-|lv|krogs|n}} * {{Z|lo}}: {{W-|lo|ຮ້ານຂາຍເບັຽ}}, {{W-|lo|ບາ}}, {{W-|lo|ຮ້ານເຫລົ້າ}}, {{W-|lo|ຮ້ານດື່ມເຫຼົ້າ}}, {{W-|lo|ຜັບ}} * {{Z|lt}}: {{W+|lt|baras|n}}, {{W-|lt|smuklė|m}} * {{Z|mk}}: {{W-|mk|бар|n}}, {{W-|mk|пивница|m}}, {{W-|mk|крчма|m}}, {{W-|mk|паб|n}} * {{Z|ms}}: {{W+|ms|bar}} * {{Z|mi}}: {{W-|mi|pā}} * {{Z|hu}}: {{W+|hu|bár}}, {{W+|hu|kocsma}}, {{W+|hu|csárda}} * {{Z|mn}}: {{W+|mn|баар}}, {{W-|mn|паб}} * {{Z|nah}}: {{W-|nah|ocnamacoyan}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|bar|n}}, {{W-|nb|drikkested|nt}}, {{W-|nb|kneipe|m|m}}, {{W+|nb|bule|m|m}}, {{W-|nb|kro}} *: {{Z|nn}}: {{W-|nn|bar|n}} * {{Z|ug}}: {{W-|ug|مەيخانا}} * {{Z|uz}}: {{W+|uz|bar}}, {{W+|uz|mayxona}}, {{W+|uz|pivoxona}} * {{Z|pl}}: {{W+|pl|bar|n}}, {{W+|pl|knajpa|m}}, {{W+|pl|gospoda|m}}, {{W+|pl|piwiarnia|m}} * {{Z|pt}}: {{W+|pt|bar|n}}, {{W+|pt|taberna|m}} * {{Z|kk}}: {{W-|kk|бар}}, {{W-|kk|сырахана}} * {{Z|ro}}: {{W+|ro|bar|nt}}, {{W+|ro|bodegă|m}}, {{W+|ro|berărie|m}}, {{W+|ro|braserie|m}} * {{Z|ru}}: {{W+|ru|бар|n}}, {{W+|ru|пивна́я|m}}, {{W+|ru|каба́к|n}}, {{W+|ru|паб|n}}, {{W+|ru|корчма́|m}}, {{W+|ru|тракти́р|n}}, {{W+|ru|таве́рна|m}}, {{W+|ru|пивну́шка|m}} * {{Z|sh}}: *: [[krîlî]]: {{W-|sh|бар|n}}, {{W-|sh|паб|n}}, {{W-|sh|крчма|m}}, {{W-|sh|пивница|m}} *: [[latînî]]: {{W+|sh|bar|n}}, {{W+|sh|pab|n}}, {{W+|sh|krčma|m}}, {{W+|sh|pivnica|m}} * {{Z|sk}}: {{W-|sk|bar|n}}, {{W+|sk|krčma|m}}, {{W+|sk|hostinec|n}} * {{Z|sl}}: {{W-|sl|bar|n}}, {{W-|sl|pivnica|m}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|kjarcma|m}} *: {{Z|hsb}}: {{W-|hsb|korčma|m}} * {{Z|es}}: {{W+|es|bar|n}}, {{W+|es|taberna|m}} * {{Z|sv}}: {{W+|sv|bar|c}}, {{W+|sv|pub|c}}, {{W+|sv|krog|c}} * {{Z|tg}}: {{W+|tg|бар}}, {{W-|tg|майхона}} * {{Z|tl}}: {{W-|tl|barikan}} * {{Z|th}}: {{W+|th|บาร์}}, {{W+|th|ผับ}}, {{W+|th|ร้านเหล้า}}, {{W-|th|ร้านสุรา}} * {{Z|tr}}: {{W+|tr|bar}}, {{W+|tr|meyhane}} * {{Z|tk}}: {{W+|tk|bar}}, {{W-|tk|meýhana}} * {{Z|bo}}: {{W-|bo|ཆང་ཁང}} * {{Z|ur}}: {{W-|ur|بار|m|tr=bār}} * {{Z|uk}}: {{W+|uk|бар|n}}, {{W-|uk|пивна́|m}}, {{W+|uk|каба́к|n}}, {{W-|uk|кна́йпа|m}}, {{W-|uk|пивни́ця|m}}, {{W-|uk|корчма́|m}}, {{W-|uk|тракти́р|n}}, {{W-|uk|паб|n}}, {{W-|uk|ши́нок|n}} * {{Z|vi}}: {{W+|vi|quán rượu}}, {{W+|vi|ba}} * {{Z|km}}: {{W+|km|បារ}}, {{W+|km|ភោជនាគារ}} * {{Z|yi}}: {{W-|yi|באַר}}, {{W-|yi|שענק}} * {{Z|el}}: {{W+|el|μπαρ|nt}}, {{W+|el|καπηλειό|nt}}, {{W+|el|ποτοπωλείο|nt}}, {{W+|el|παμπ|m}} *: {{Z|grc}}: {{W-|grc|καπηλεῖον|nt}} {{werger-bin}} === Navdêr 5 === {{navdêr|ku|z=n}} # [[rewş]], [[hal]], [[barûdox]], [[weziyet]] #: {{mk|ku|'''barê''' neasayî|rewşa [[awarte]]|birêz=1}} ==== Etîmolojî ==== Vê dawiyê ji bi rêya {{w|soranî}} ji {{ji|fa|ku|بار|tr=bar|w=[[car]], [[derfet]], [[delîve]]}}. ==== Werger ==== {{werger-bnr|rewş}} === Navdêr 6 === {{navdêr|ku|z=m}} # [[yeke]]ya [[pîvan]]a [[zext]] û [[fişar]]ê #* {{bêmînak|ku}} ==== Etîmolojî ==== Ji {{deyn|en|ku|bar}} ji {{ji|grc|ku|βᾰ́ρος|tr=báros}}. ==== Werger ==== {{werger-ser}} * {{Z|en}}: {{W+|en|bar}} (unit for measuring pressure) {{werger-bin}} === Navdêr 7 === {{navdêr|ku|z=m}} # [[barebar]], [[barrîn]], [[deng]]ê [[barrîn]]ê #* {{bêmînak|ku}} ==== Etîmolojî ==== {{onom|ku}}. ==== Werger ==== {{werger-ser}} {{werger-bin}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza}} # [[par]], [[behr]], [[pişk]], [[qism]], [[qismet]] #* {{bêmînak|zza}} == {{ziman|ckb}} == === Navdêr === {{navdêr|ckb|sc=Latn}} # [[bar#Kurmancî|bar]], [[piştî]] #* {{bêmînak|ckb}} # [[rewş]], [[hal]], [[barûdox]], [[bar#Kurmancî|bar]] #* {{bêmînak|ckb}} # [[bar#Kurmancî|bar]], [[meyxane]] #* {{bêmînak|ckb}} == {{ziman|aa}} == === Navdêr === {{navdêr|aa}} # {{f|aa|dem}} [[şev#ku|şev]] #* {{bêmînak|aa}} == {{ziman|sq}} == === Navdêr === {{navdêr|sq|z=n}} # {{f|sq|riwek}} [[giya#ku|giya]] #* {{bêmînak|sq}} == {{ziman|de}} == === Bilêvkirin === * {{IPA|de|[baːɐ̯]}} * {{deng|de|De-bar.ogg|Deng}} * {{deng|de|De-bar2.ogg|Deng|dever=Berlîn, Almanya}} * {{kîte|de|bar}} === Rengdêr === {{rengdêr|de}} # (pereyê) [[pêşîn]], [[neqd]] #* {{bêmînak|de}} == {{ziman|dlm}} == === Lêker === {{lêker|dlm}} # [[vexwarin#ku|vexwarin]] #* {{bêmînak|dlm}} == {{ziman|gl}} == === Navdêr === {{navdêr|gl|z=n}} # {{mijar|gl|avahî}} {{g|ku|qehwexane}} #* {{bêmînak|gl}} === Çavkanî === {{rûpela wergerê|gl|qehwexane}} == {{ziman|en}} == === Bilêvkirin === * {{deng|en|en-us-bar.ogg|dever=DYA}} * {{deng|en|en-uk-baa.ogg|dever=QY}} * {{deng|en|LL-Q1860 (eng)-Wodencafe-bar.wav|Deng|dever=Teksas, DYA}} * {{deng|en|LL-Q1860 (eng)-Grendelkhan-bar.wav|Deng|dever=Connecticut, DYA}} === Navdêr === {{navdêr|en}} # [[qalib]]: perçeya tiştekî ya çarqorzî #* {{bêmînak|en}} # bar, [[meyxane]], [[badexane]] #* {{bêmînak|en}} # [[şifşe]] #* {{bêmînak|en}} == {{ziman|ssy}} == === Navdêr === {{navdêr|ssy}} # {{f|ssy|dem}} [[şev#ku|şev]] #* {{bêmînak|ssy}} == {{ziman|rom}} == === Navdêr === {{navdêr|rom}} # {{f|rom|erdnîgarî}} {{g|ku|çiya}} #* {{bêmînak|rom}} === Çavkanî === {{rûpela wergerê|rom|çiya}} == {{ziman|it}} == === Bilêvkirin === * {{deng|it|LL-Q652 (ita)-Ciampix-bar.wav|Deng|dever=Îtalya}} === Navdêr === {{navdêr|it|z=n}} # {{mijar|it|avahî}} {{g|ku|qehwexane}} #* {{bêmînak|it}} === Çavkanî === {{rûpela wergerê|it|qehwexane}} == {{ziman|tr}} == === Navdêr === {{navdêr|tr}} # [[bar#Kurmancî|bar]], [[meyxane]] #* {{bêmînak|tr}} # [[cure]]yekî [[govend]]ê ye ku bi piranî li aliyê Erzirom û bajarên li derdora wê tê leyistin. #* {{bêmînak|tr}} # [[deleme]] #* {{bêmînak|tr}} # [[tebeq]], [[kerme]] #: {{mk|tr|Dili '''bar''' tutmuştu.|Zimanê wî tebeqî bûbû.|birêz=1}} == {{ziman|wbl}} == === Navdêr === {{navdêr|wbl}} # [[derî]], [[dergeh]] #* {{bêmînak|wbl}} h6r3jpey9lydzdpmv3ernjmot6onu4d erd 0 9514 6291746 6262020 2026-07-27T23:11:52Z Ghybu 1393 /* Navdêr 2 */ 6291746 wikitext text/x-wiki {{bnr-h|êrd|Erd}} == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/ʕɜɾd/}} * {{deng|ku|LL-Q36368 (kur)-Dildadil-erd.wav|Deng|dever=Amed}} * {{deng|ku|Ku-erd.ogg|Deng|Êlih}} * {{deng|ku|LL-Q36163 (kmr)-Key Mîrza-erd.wav|Deng|Bidlîs}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|erd|mê}} {{navdêr|ku|z=m}} # [[cih|Cih]], [[der]] û [[zemîn]]ên ku em [[pê lê kirin|pê lê dikin]]. #* {{jêder-kovar|ku|jêgirtin=Darên kesk tev reş bûn. Giyayê teze tev bû pîşo. Fêkiyên li ser daran çilmisîn. Pel tev weşiyan. Qurmên daran bûn rejî, yek bi ser yekê de qulipîn '''erdê'''...|kovar=Kovara {{w|Bîrnebûn}}|hejmar=71|sal=2018|sernav=Li welatê min bihar tê|nivîskar=Hesen Huseyîn Denîz|rûpel=31}} #* ''Hem kelî ew behr û kef da û dûxan,</br>Kef bûye '''erd''' û dûxan bû asîman.</br>Nîveka dî çêkirin jê çarî çîz'' {{Jêgirtin/Mela Hisênê Bateyî/Mewlûda Kurdî}} ==== Bi alfabeyên din==== * {{ku-ar|عه‌رد}}, {{g|ku|sc=Arab|ئه‌رد}} ==== Formên alternatîv ==== {{kol3|ku| | 'erd | erz | 'erz | edir | edr | 'edir | 'edr }} ==== Jê ==== {{kol3|ku| | bêerd | bêerdî | bierd | bierdî | binerd | binerdî | erddar | erddarî | erdî | sererd | sererdî }} ==== Etîmolojî ==== Li ser etîmoljiya peyva kurdî ''erd'' lihevkirin di navbera zimannasên kurdî de peyda nebûye. Bi dibetiya mezin, ji [[proto-hindûewropî]] *h₁er- tê. Hevreha zazakî ''erd''. Li gorî hin çavkaniyan, peyva ''erd'' ji {{ji|ar|ku|أرض|tr=erḍ}} (erd, ax, zevî) tê. Hevreha akadî [[𒆠]] (erṣetu), aramî [[ܐܪܥܐ]] / [[ארעא]] (era'), {{hv|he|ארץ|tr=eretz}}. Ew hemû ji proto-samî {{recons|ʾarṣ́-}}. Lê ev teorî muhtemelen ji bo kurmanciyê ne rast e, ji ber ku dengê ku ji aliyê tîpa erebî ya "ض"(ḍ) ve tê nimandin di kurdî de bi giştî dibe dengê tîpa kurdî ya "z" (îngl. voiced alveolar fricative). Bo nimûne: raḍi > razî, remeḍan > remezan. Vê guhartinê li zaravayê soranî û li zimanên farsî û ûrdû rû da: {{hv|ckb|عه‌رز}}, {{hv|fa|ارض|tr=erz}}, ûrdûyî {{g|ur|ارض|tr=erz}} Yanî, heye ku peyva ''erz'' ya ku di soranî, farsî û ûrdû de tê bi kar anîn ji {{ji|ar|ku|أرض|tr=erḍ}} tê. Lê belê, ev herwiha ji bo kurmanciyê nikare bê gotin. Ji ber vê yekê, peyva ''erd'' hevreheke çewt (false cognate) a peyva erebî أرض (erḍ) e û muhtemelen peyveke proto-hindûewropî ye. [[Rast e, hevwate ya peyva "earth" ya Îngilîzî ye. Etîmolojiya peyva "earth": https://en.wiktionary.org/wiki/earth ]] ;{{biçûk|Çavkanî: * Muhammed, Husein. Rehnas. Ferhenga etîmolojî ya kurdî. Kurdish Etymological Dictionary * {{Chyet}} * {{Dihxoda}} * {{Tsabolov}} }} ==== Werger ==== {{werger-ser}} * {{Z|fr}}: {{W+|fr|sol|n}}, {{W+|fr|terre ferme|m}} * {{Z|en}}: {{W+|en|ground}}, {{W+|en|earth}} * {{Z|tr}}: {{W+|tr|yer}}, {{W+|tr|zemin}}, {{W+|tr|yer yüzü}} {{werger-bin}} === Navdêr 2 === {{ku-tewîn-nav|erd|nêr|alt.çem.yj='''ê'''rd}} {{navdêr|ku|z=n}} # [[xwelî]], [[ax]] #* {{bêmînak|ku}} # [[zevî]] #* {{jêder|ku|jêgirtin=Ew ê niha ji nava '''erdan''' werin. Hê ro nuh çûye ava.|''[[w:Dara Hinarê|Dara Hinarê]]'', [[w:Yaşar Kemal|Yaşar Kemal]], Weşanên [[w:Nûdem|Nûdem]]}} # [[erazî]], [[milk]] #* {{bêmînak|ku}} # [[welat]] #* {{bêmînak|ku}} ==== Werger ==== {{werger-ser|xwelî, ax}} * {{Z|fr}}: {{W+|fr|terre|m}} * {{Z|tr}}: {{W+|tr|toprak}} {{werger-bin}} {{werger-ser|zevî}} * {{Z|fr}}: {{W+|fr|champ|n}} * {{Z|en}}: {{W+|en|farmland}} * {{Z|tr}}: {{W+|tr|tarla}} {{werger-bin}} {{werger-ser|erazî, milk}} * {{Z|fr}}: {{W+|fr|domaine|n}}, {{W+|fr|propriété|m}} * {{Z|en}}: {{W+|en|property}}, {{W+|en|estate}} * {{Z|tr}}: {{W+|tr|arazi}} {{werger-bin}} {{werger-ser|welat}} * {{Z|fr}}: {{W+|fr|pays|n}} * {{Z|en}}: {{W+|en|country}} * {{Z|tr}}: {{W+|tr|ülke}} {{werger-bin}} av235fa0qn6j475mk9ol9lks1l105ym nan 0 9605 6291750 6262225 2026-07-27T23:14:38Z Ghybu 1393 /* Navdêr */ 6291750 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/nʌːn/}} * {{kîte|ku|nan}} * {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-nan.wav|Deng|dever=Bidlîs}} === Navdêr === {{ku-tewîn-nav|nan|nêr|alt.çem.yj=n'''ê'''n}} [[Wêne:Nan Bismil 2010.JPG|thumb|(1) Çend '''nanên''' [[Bismil]]ê.]] [[Wêne:Nane tennur.jpg|thumb|(1) '''Nanê''' tenûrê.]] {{navdêr|ku|z=n}} # {{f|ku|xwarin}} [[hevîr|Hevîr]]ê [[pêjan|pêjayî]]. #* {{jêder|ku|jêgirtin=Sala ko paîzxêr zû bikeve pê re nagîhin kuta bikin, guşiyên genim dixin xaniyan. '''Nanê''' wan gelekî tamdare.|''{{w|Ronahî (kovar)}}'', ''ZAD Û GENIM'', 1942}} #* {{jêder|ku|{{Jêgirtin/Ehmedê Xanî/Mem û Zîn}}|jêgirtin=Qet'a çu nebû ne xur ne xwabek</br>Wan bîr nedihat-i '''nan''' û abek</br>Ew hefte temam bûye gerdek}} #* {{jêder|ku|jêgirtin=Goya li nik wan şûm e, ewî '''nanê''' (ko) ibtida (destpêkê) dipêjin û ji tenûrê biderdikevitin ew naxwin. Goya herçî wî '''nanî''' bixutin jina wî dimiritin.|{{jêgirtin/Mele Mehmûdê Bayezîdî/Adat û Rusûmatnameê Ekradiye|r=105}}}} # [[xwarin]], [[xwirak]], [[xwaremenî]], tişta/ê tê [[xwarin]] ==== Bi alfabeyên din ==== * {{ku-ar|نان}} * {{ku-kr|нан}} ==== Formên alternatîv ==== {{kol3|ku|cure=Herwiha |non |nun |nên |nîn }} ==== Jornav ==== * {{g|ku|xwarin}} ==== Jêrnav ==== {{kol3|ku |berwesêl |berweste |destenan |kût |kûtêşa |nanê loş |[[nanê vêtîr]], [[nanê fetîr]] |[[nanê bêhavên]], [[nanê bêhêvên]] |nanê helîte |[[nanê hilhatî]], [[nanê hilehtî]] |[[nanê mêzînê]], [[nanê firneyê]] |[[nanê patîleyî]], yan tenê [[patîle]] |nanê sêlê |[[nanê şikeva]], [[galeta]] |[[nanê tenûrê]], [[nanê tendûrê]] |nanê tirş |nanê toraqê |nanê tûj |nanê şilikî |nanê tenik |nanê mişeliqê |[[nanê mîr]], [[nanê xweşik]] |[[pate]], [[patot]] |rikak |[[teptepe]], [[nanê temayan]], [[nanê qulqulî]] |[[totiknan]], [[totik]] |xerwal |nanê kakilê |[[nanê garis]], [[nanê garisî]] |nanê pincarê |[[nanê rûs]], [[nanê ûris]] |nanê [[etor]] |nanê [[pilûrkî]] |nanê [[ceh]]î |nanê [[firin]]ê |nanê [[genim]]î | nanê [[semon]] | nanê [[sewik]] | nanê [[sêl]]ê | nanê [[tenûr]]ê }} ==== Têkilî ==== {{kol3|ku |[[ard]], [[ar]] |firin |hevîr |kuçk |sêl |tenûr |tîrok |xwank |nûrî<w:destekê nanî> }} ==== Jê ==== {{kol3|ku|cure=Jê |nan patin<pos:lêker> |nan pehtin<pos:lêker> |nan pêjan |nan pêjandin |nan pêjîn |nanpatin<pos:navdêr> |nanpehtin<pos:navdêr> |nanpêjan<pos:navdêr> |nanpêjandin |nanpêjîn |bênanûxwê |nanek |nanik |nankor |nankorî |nanpêj |nanpêjî |nanxwer }} ==== Etîmolojî ==== Hevreha soranî {{g|ckb|نان}}, [[kurdiya başûrî]] ''nan'', lekî ''nan'', hewramî ''nan'', zazakî {{q|zza|nan}} / {{q|zza|non}}, farisî {{g|fa|نان|tr=nan}} (farisiya devkî {{g|fa|نون‎|tr=nûn}}, tacikî [[нон]] (non), pehlewî [[𐭭𐭠𐭭‎]] (nan), belûçî {{g|bal|نگن|tr=negen}}, partî ''n'g'n'' (neġn), peştûyî {{g|ps|نغن|tr=neġen}}, ji {{ji|ira}}, bi îraniya kevn ''[[*nagna-]]'' (/negne-/). [[Şablon:Lubotsky|Lubotsky]] peyva îranî bi peyva sanskrîtî [[नग्नहु]] (nagnahu: [[havên]]) ve girê dide û dibêje ku ew herdu ji {{ji|ira-pro||-}} ne. Lê mimkin e ku ''nan'' peyveke kevnar ya Rojhilata Navîn ya ji zimanekî ne-hindûewropî jî be, bidin ber sûmerî [[𒃻]] ([NINDA]). Di hîtîtî de jî peyv bi heman awayî hatiye qeydkirin lê nayê zanîn ka divê ew di hîtîtî de çawa were gotin/xwandin. Peyva ''nan'' bi berfirehî di zimanên Hindistanê û Asyaya Navîn de jî heye lê ew ji zimanên îranî hatine wergirtin: ûrdûyî {{g|ur|نان‎|tr=nan}}, hindî [[नान]] (nān), kirgîzî û qazaxî [[нан]] (nan), ozbekî ''[[non]]'', oyxurî {{g|ug|نان‎|tr=nan}}, çînî [[饢]] / [[馕]] (náng), nenetsî [[нянь]] (nyani)... Ji hindî peyv bi maneya cûreyek nanê rojhilatî bi awayê ''[[naan]]'' ketiye hemû zimanên ewropî jî. Peyva ''nan'' dişibe [[hevreh]]a xwe ya zimanên romî: latînî ''[[panis]]'', spanî ''[[pan]]'', fransî ''[[pain]]''... lê ew û ''nan'' ne [[hevreh]]ên hev in çunkî veguhastina N/P di peyvên din de peyda nabe. ;{{biçûk|Çavkanî: * {{Chyet}} * {{Horn}} * {{Lubotsky}} * {{MacKenzie}} * {{Mayrhofer}} * {{Pokorny}} * {{Tsabolov}} }} ==== Werger ==== {{werger-ser|xwarina ku ji ardî û avê hatiye çêkirin|1}} * {{Z|ab}}: {{W-|ab|амгьал}}, {{W-|ab|ача}} * {{Z|ady}}: {{W-|ady|хьэлэгъу}}, {{W-|ady|хьалыгъу}} * {{Z|aa}}: {{W-|aa|gaqambo}} * {{Z|af}}: {{W-|af|brood}} * {{Z|akk}}: {{W-|akk|𒃻|ts=ak(a)lu|tr=NINDA}} * {{Z|sq}}: {{W-|sq|bukë|m}} * {{Z|de}}: {{W-|de|Brot|nt}} * {{Z|atv}}: {{W-|atv|этпек|cuda=этпе́к}} * {{Z|alt}}: {{W-|alt|ӧтпӧк}}, {{W-|alt|аш}}, {{W-|alt|калаш|cuda=ка́ла́ш}}, {{W-|alt|нан}} * {{Z|ems}}: {{W-|ems|kelipaq}} * {{Z|abs}}: {{W-|abs|roti}} * {{Z|am}}: {{W-|am|ዳቦ}} * {{Z|an}}: {{W-|an|pan}} * {{Z|arc}}: *: Îbranî: {{W-|arc|לחמא|n|tr=lakhmā, lakhmo}} *: Siryanî: {{W-|arc|ܠܚܡܐ|n|tr=lakhmā, lakhmo}} * {{Z|agj}}: {{W-|agj|ዳቦ|tr=dabo}} * {{Z|rup}}: {{W-|rup|pãni|m}}, {{W-|rup|pãne|m}} * {{Z|ast}}: {{W-|ast|pan|n}} * {{Z|ain}}: {{W-|ain|パン|tr=pan}}, {{W-|ain|ヘリェバ|tr=heryeba}} * {{Z|az}}: {{W-|az|çörək}} * {{Z|eu}}: {{W-|eu|ogi}} * {{Z|ba}}: {{W-|ba|икмәк}} * {{Z|bbl}}: {{W-|bbl|მაჲჴი̆}} * {{Z|bar}}: {{W-|bar|Brod}}, {{W-|bar|Loawe}} * {{Z|be}}: {{W-|be|хлеб|n}} * {{Z|bal}}: {{W-|bal|نان|tr=nán}}, {{W-|bal|نگن|tr=nagan}} * {{Z|bn}}: {{W+|bn|রুটি}}, {{W+|bn|পাঁউরুটি}}, {{W+|bn|লোফ}} * {{Z|bcl}}: {{W-|bcl|tinapay}} * {{Z|br}}: {{W-|br|bara|n}} * {{Z|bdk}}: {{W-|bdk|фу}} * {{Z|bg}}: {{W-|bg|хляб|n}} * {{Z|my}}: {{W+|my|ပေါင်မုန့်}} * {{Z|kac}}: {{W-|kac|muk}} * {{Z|ce}}: {{W-|ce|бепиг}} * {{Z|cs}}: {{W-|cs|chléb|n}}, {{W+|cs|chleba|n}} * {{Z|chr}}: {{W-|chr|ᎦᏚ}} * {{Z|ny}}: {{W-|ny|buledi}} * {{Z|cic}}: {{W-|cic|paska}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|麵包}}, {{W-|yue|包|tr=baau1}} *: {{Z|dng}}: {{W-|dng|мәмә}} *: {{Z|cmn}}: {{W+|cmn|麵包}} *: {{Z|cdo}}: {{W-|cdo|麵包}} *: {{Z|nan}}: {{W-|nan|麵包|tr=mī-pau}} *: {{Z|wuu}}: {{W-|wuu|麵包}} * {{Z|cv}}: {{W-|cv|ҫӑкӑр}}, {{W-|cv|тырӑ}} * {{Z|dlm}}: {{W-|dlm|pun|n}}, {{W-|dlm|puan|n}}, {{W-|dlm|pen|n}} * {{Z|da}}: {{W-|da|brød|nt}} * {{Z|ovd}}: {{W-|ovd|bröð|nt}} * {{Z|id}}: {{W+|id|roti}} * {{Z|ar}}: {{W+|ar|خُبْز|n}} *: {{Z|arq}}: {{W-|arq|اغروم|n|tr=aḡrum}} *: {{Z|arz}}: {{W-|arz|عيش|n|tr=ʕēš}} *: {{Z|acw}}: {{W-|acw|خُبز|n|tr=ḵubuz}}, {{W-|acw|عيش|n|tr=ʕēš}} *: {{Z|acm}}: {{W-|acm|صمّون|n|tr=ṣammūn}} *: {{Z|ary}}: {{W-|ary|خبز|n|tr=ḵobz}}, {{W-|ary|قرص|n|tr=gərṣ}} *: {{Z|apc}}: {{W-|apc|خِبِز|n|tr=ḵebez}} *: {{Z|ajp}}: {{W-|ajp|خِبِز|n|tr=ḵubez}} *: {{Z|apd}}: {{W-|apd|عيش|tr=ʕēš}} * {{Z|hy}}: {{W+|hy|հաց}} * {{Z|eo}}: {{W-|eo|pano}} * {{Z|et}}: {{W+|et|leib}} * {{Z|ee}}: {{W-|ee|abolo|nt}} * {{Z|gur}}: {{W-|gur|pãanɛ}}, {{W-|gur|borborɩ}} * {{Z|fa}}: {{W-|fa|نان|tr=nân}}, {{W-|fa|نون|tr=nun}}, {{W-|fa|چُرَک|tr=čorak}}, {{W-|fa|چورَک|tr=čurak}} *: {{Z|pal}}: {{W-|pal|𐭭𐭠𐭭|ts=nān}} * {{Z|fo}}: {{W+|fo|breyð|nt}} * {{Z|xpg}}: {{W-|xpg|βεκος|ts=begos}} * {{Z|fj}}: {{W-|fj|madrai}} * {{Z|fi}}: {{W+|fi|leipä}} * {{Z|fr}}: {{W+|fr|pain|n}} *: {{Z|fro}}: {{W-|fro|pain|n}} *: {{Z|frm}}: {{W-|frm|pain|n}} * {{Z|fur}}: {{W-|fur|pan}} * {{Z|frr}}: {{W-|frr|Bruar}} * {{Z|stq}}: {{W-|stq|Brood}} * {{Z|fy}}: {{W-|fy|bôle|g}}, {{W-|fy|brea|nt}} * {{Z|ff}}: *: Adlamî: {{W-|ff|𞤥𞥋𞤦𞤵𞤪𞤵}} *: Latînî: {{W-|ff|mburu}} * {{Z|gd}}: {{W-|gd|aran|n}} * {{Z|gl}}: {{W+|gl|pan|n}}, {{W+|gl|broa|m}} * {{Z|got}}: {{W-|got|𐌷𐌻𐌰𐌹𐍆𐍃|n}} * {{Z|gu}}: {{W-|gu|રોટલી}} * {{Z|ka}}: {{W-|ka|პური}} * {{Z|gn}}: {{W-|gn|mbupaje}} * {{Z|ht}}: {{W-|ht|pen}} * {{Z|haw}}: {{W-|haw|palaoa}} * {{Z|ha}}: {{W-|ha|gùr̃āsā̀|m}} * {{Z|hi}}: {{W+|hi|रोटी|m}}, {{W+|hi|नान|m}}, {{W-|hi|ब्रेड}} * {{Z|hit}}: {{W-|hit|𒉒|tr=NÍNDA}} * {{Z|mww}}: {{W-|mww|mov ci}} * {{Z|nl}}: {{W+|nl|brood|nt}} * {{Z|huz}}: {{W-|huz|баба}} * {{Z|he}}: {{W-|he|לֶחֶם|n|tr=lékhem}} * {{Z|io}}: {{W+|io|pano}} * {{Z|ang}}: {{W-|ang|hlāf|n}}, {{W+|ang|brēad|nt}} * {{Z|enm}}: {{W-|enm|bred}} * {{Z|en}}: {{W-|en|bread}} * {{Z|ia}}: {{W+|ia|pan}} * {{Z|iu}}: {{W-|iu|ᕿᖂᔭᖅ}} * {{Z|ga}}: {{W+|ga|arán|n}} *: {{Z|sga}}: {{W-|sga|arán|n}}, {{W-|sga|bairgen|m}} * {{Z|ist}}: {{W-|ist|pan|n}} * {{Z|it}}: {{W+|it|pane|n}} * {{Z|is}}: {{W+|is|brauð|nt}} * {{Z|ja}}: {{W+|ja|パン|tr=pan}} * {{Z|jv}}: {{W+|jv|roti}} * {{Z|kbd}}: {{W-|kbd|щӏакхъуэ}} * {{Z|kl}}: {{W-|kl|iffiaq}} * {{Z|kln}}: {{W-|kln|maghatiat}} * {{Z|xal}}: {{W-|xal|өдмг}} * {{Z|kn}}: {{W+|kn|ಬ್ರೆಡ್}}, {{W+|kn|ರೊಟ್ಟಿ}} * {{Z|pam}}: {{W-|pam|tinape}} * {{Z|krc}}: {{W-|krc|ётмек|tr=ötmek}}, {{W-|krc|ётме|tr=ötme}}, {{W-|krc|гыржын}} * {{Z|csb}}: {{W-|csb|chléb|n}} * {{Z|ca}}: {{W+|ca|pa|n}} * {{Z|qu}}: {{W-|qu|t'anta}}, {{W-|qu|tanta}} * {{Z|kjj}}: {{W-|kjj|баба}} * {{Z|ky}}: {{W+|ky|нан}}, {{W+|ky|тамак}}, {{W+|ky|ар}}, {{W+|ky|оокат}}, {{W+|ky|азык}}, {{W+|ky|камсыздандырылуу}} * {{Z|ki}}: {{W-|ki|mũgate|c3}} * {{Z|si}}: {{W+|si|පාන්}} * {{Z|koi}}: {{W-|koi|нянь}} * {{Z|ko}}: {{W+|ko|빵}} * {{Z|kw}}: {{W-|kw|bara|n}} * {{Z|kmv}}: {{W-|kmv|djipẽ}} * {{Z|vkp}}: {{W-|vkp|pãw}} * {{Z|crk}}: {{W-|crk|ᐅᐦᐱᐦᑲᓯᑲᐣ|tr=ohpihkasikan}}, {{W-|crk|ᐸᐦᑵᓯᑲᐣ|tr=pahkwêsikan}}, {{W-|crk|ᐲᓷᐦᑲᓯᑲᐣ|tr=pîswêhkasikan}} * {{Z|cr}}: {{W-|cr|ᐱᓷᐦᑲᓯᑲᐣ}} * {{Z|kum}}: {{W-|kum|экмек}} * {{Z|ltg}}: {{W-|ltg|maize|m}} * {{Z|la}}: {{W+|la|panis|n}} * {{Z|lv}}: {{W+|lv|maize}} * {{Z|lo}}: {{W-|lo|ຂນົມປັງ}}, {{W+|lo|ເຂົ້າຈີ່}}, {{W-|lo|ປັງ}} * {{Z|lez}}: {{W-|lez|фу}} * {{Z|li}}: {{W-|li|wegk|n}} * {{Z|lt}}: {{W+|lt|duona|m}} * {{Z|lmo}}: {{W-|lmo|pan|n}} * {{Z|khb}}: {{W-|khb|ᦶᦖᧃᧈᦗᧁᧈ}}, {{W-|khb|ᦃᧁᧉᦓᦳᧄᦔᧂ}}, {{W-|khb|ᦃᧁᧉᦶᦖᧃᧈᦗᧁᧈ}} * {{Z|luy}}: {{W-|luy|kumkate}}, {{W-|luy|ekeki}} * {{Z|lb}}: {{W+|lb|Brout|nt}} * {{Z|xlu}}: {{W-|xlu|𒉒|tr=NÍNDA}} * {{Z|mhn}}: {{W-|mhn|proat|nt}} * {{Z|mk}}: {{W-|mk|леб|n}} * {{Z|mg}}: {{W+|mg|mofo}}, {{W+|mg|dipaina}} * {{Z|ml}}: {{W+|ml|റൊട്ടി}}, {{W+|ml|അപൂപം}} * {{Z|ms}}: {{W+|ms|roti}} * {{Z|mt}}: {{W-|mt|ħobż|n}} * {{Z|mnc}}: {{W-|mnc|ᡝᡶᡝᠨ}} * {{Z|gv}}: {{W+|gv|arran|n}} * {{Z|mi}}: {{W+|mi|parāoa}} * {{Z|mr}}: {{W-|mr|रोटी|m}}, {{W-|mr|भाकरी|m}}, {{W+|mr|पाव|n}} * {{Z|wam}}: {{W-|wam|petukqunneg}} * {{Z|yua}}: {{W-|yua|waaj}} * {{Z|gun}}: {{W-|gun|mbojape}} * {{Z|hu}}: {{W+|hu|kenyér}} * {{Z|egy}}: {{W-egy|t|n|h=t:X2-X4:Z2}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|талх}}, {{W-|mn|миянбуу}} *: Mongolî: {{W-|mn|ᠲᠠᠯᠬ᠎ᠠ}}, {{W-|mn|ᠮᠢᠶᠠᠨᠪᠣᠤ}} * {{Z|umu}}: {{W-|umu|ăpwáan}} * {{Z|wmw}}: {{W-|wmw|nkate}} * {{Z|nci}}: {{W-|nci|tlaxcalli}}, {{W-|nci|Caxtīllān tlaxcalli}} * {{Z|nap}}: {{W-|nap|pane|n}}, {{W-|nap|ppane|nt}} * {{Z|nv}}: {{W-|nv|bááh}} * {{Z|nds}}: *: {{Z|nds-nl}}: {{W-|nds-nl|stoet}} *: {{Z|nds-de}}: {{W-|nds-de|Braud|nt}} ; {{W-|nds-de|Brod|nt}}, {{W-|nds-de|Broot|nt}}, {{W-|nds-de|Brot|nt}} * {{Z|yrk}}: {{W-|yrk|нянь}} * {{Z|ne}}: {{W-|ne|रोटी}} * {{Z|niv}}: {{W-|niv|леп}} * {{Z|nog}}: {{W-|nog|оьтпек}} * {{Z|nrf}}: {{W-|nrf|pain|n}}, {{W-|nrf|pôin|n}} * {{Z|non}}: {{W-|non|brauð|nt}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|brød|nt}} *: {{Z|nn}}: {{W+|nn|brød|nt}} * {{Z|oj}}: {{W-|oj|bakwezhigan}} * {{Z|oc}}: {{W+|oc|pan|n}} * {{Z|os}}: {{W-|os|дзул}} * {{Z|ota}}: {{W-|ota|اكمك|tr=ekmak}}, {{W-|ota|نان|tr=nan}}, {{W-|ota|خبز|tr=hubz}} * {{Z|ug}}: {{W+|ug|نان}} * {{Z|uz}}: {{W+|uz|non}} * {{Z|pap}}: {{W-|pap|pan}} * {{Z|ps}}: {{W+|ps|ډوډۍ|m|tr=ḍoḍëy}} * {{Z|pms}}: {{W-|pms|pan|n}} * {{Z|pdt}}: {{W-|pdt|Broot|nt}} * {{Z|pox}}: {{W-|pox|sťaibä|m}} * {{Z|pl}}: {{W+|pl|chleb|n}} * {{Z|pt}}: {{W+|pt|pão|n}} * Puncabî: *: Şaxmuxî: {{W+|pa|روٹی|m}} *: Gurmuxî: {{W+|pa|ਰੋਟੀ|m}} * {{Z|kk}}: {{W+|kk|нан}} * {{Z|cop}}: {{W-|cop|ⲟⲉⲓⲕ}} * {{Z|rap}}: {{W-|rap|haraoa}} * {{Z|rm}}: {{W-|rm|paun}} * {{Z|rom}}: {{W-|rom|manro|n}} * {{Z|ro}}: {{W+|ro|pâine|m}}, {{W-|ro|pâne|m}} * {{Z|ru}}: {{W+|ru|хлеб|n}} * {{Z|rue}}: {{W-|rue|хлїб|n}} * Samî: *: {{Z|smn}}: {{W-|smn|leibi}} *: {{Z|smj}}: {{W-|smj|láibbe}} *: {{Z|se}}: {{W-|se|láibi}} *: {{Z|sje}}: {{W-|sje|lajjbe}} *: {{Z|sms}}: {{W-|sms|leiˊbb}} *: {{Z|sma}}: {{W-|sma|laejpie}} *: {{Z|sju}}: {{W-|sju|laajpee}} * {{Z|sm}}: {{W-|sm|falaoa}} * {{Z|sgs}}: {{W-|sgs|douna}} * {{Z|sa}}: {{W+|sa|रोटी|m}} * {{Z|sat}}: {{W-|sat|ᱯᱤᱴᱷᱟ}} * Sardinian: *: {{Z|sc}}: {{W-|sc|pani|n}} * {{Z|ceb}}: {{W-|ceb|tinapay}} * {{Z|scn}}: {{W+|scn|pani}} * {{Z|sid}}: {{W-|sid|daabbo}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хле̏б|n}}, {{W-|sh|хље̏б|n}}, {{W-|sh|кру̏х|n}}, {{W-|sh|кру̏в|n}} *: Latînî: {{W+|sh|hlȅb|n}}, {{W+|sh|hljȅb|n}}, {{W+|sh|krȕh|n}}, {{W+|sh|krȕv|n}} * {{Z|sco}}: {{W-|sco|breid}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|хлѣбъ|n}} * {{Z|orv}}: {{W-|orv|хлѣбъ|n}} * {{Z|sk}}: {{W+|sk|chlieb|n}} * {{Z|sl}}: {{W+|sl|kruh|n}} * {{Z|so}}: {{W+|so|rooti|n}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|klěb|n}} *: {{Z|hsb}}: {{W+|hsb|chlěb|n}} * {{Z|st}}: {{W+|st|bohobe}} * {{Z|es}}: {{W+|es|pan|n}} * {{Z|sux}}: {{W-|sux|𒉒|tr=NÍNDA}} * {{Z|sva}}: {{W-|sva|დია̈რ}} * {{Z|sw}}: {{W+|sw|mkate|3|4}} * {{Z|sv}}: {{W+|sv|bröd|nt}} * {{Z|shn}}: {{W-|shn|ၶဝ်ႈမုၼ်း}} * {{Z|zdj}}: {{W-|zdj|mkatre|c3}} * {{Z|tab}}: {{W-|tab|уьл}} * {{Z|tg}}: {{W+|tg|нон}}, {{W+|tg|чӯрак‍}} * {{Z|tl}}: {{W+|tl|tinapay}} * {{Z|ta}}: {{W+|ta|ரொட்டி}} * {{Z|rif}}: {{W-|rif|aɣṛum|n}} * {{Z|shi}}: {{W-|shi|ⴰⵖⵔⵓⵎ|n}} * {{Z|th}}: {{W+|th|ขนมปัง}}, {{W+|th|ปัง}} * {{Z|te}}: {{W+|te|బ్రెడ్}}, {{W-|te|బ్రెడ్డు}}, {{W+|te|రొట్టె}} * {{Z|tzm}}: {{W-|tzm|ⴰⵖⵔⵓⵎ|n}} * {{Z|crh}}: {{W-|crh|ötmek}} * {{Z|tt}}: {{W+|tt|икмәк}}, {{W+|tt|ашлык}}, {{W+|tt|ипи}} * {{Z|tet}}: {{W-|tet|paun}} * {{Z|ti}}: {{W-|ti|ባኒ}} * {{Z|tr}}: {{W+|tr|ekmek}}, {{W+|tr|banak}} * {{Z|tk}}: {{W+|tk|çörek}} * {{Z|bo}}: {{W-|bo|གོ་རེ}} * {{Z|txb}}: {{W-|txb|kanti}} * {{Z|ts}}: {{W+|ts|xinkwa}} * {{Z|tta}}: {{W-|tta|waksakpai}} * {{Z|tzo}}: {{W-|tzo|kaxlan vaj}} * {{Z|udm}}: {{W-|udm|нянь}} * {{Z|uga}}: {{W-|uga|𐎍𐎈𐎎}}, {{W-|uga|𐎒𐎒𐎆}} * {{Z|umb}}: {{W-|umb|ombolo}} * {{Z|ur}}: {{W-|ur|روٹی|m|tr=roṭī}}, {{W-|ur|نان|m|tr=nān}} * {{Z|uk}}: {{W+|uk|хліб|n}} * {{Z|vec}}: {{W+|vec|pan|n}} * {{Z|vep}}: {{W-|vep|leib}} * {{Z|vi}}: {{W+|vi|bánh mì}}, {{W+|vi|bánh mỳ}}, {{W-|vi|bánh tây}} * {{Z|vo}}: {{W+|vo|bod}} * {{Z|vro}}: {{W-|vro|leib}} * {{Z|vot}}: {{W-|vot|leipe}} * {{Z|wa}}: {{W+|wa|pwin|n}}, {{W+|wa|pan|n}} * {{Z|cy}}: {{W+|cy|bara|n}} * {{Z|wym}}: {{W-|wym|brūt|nt}} * {{Z|ane}}: {{W-|ane|pêê}} * {{Z|km}}: {{W-|km|នំប៉័ង}}, {{W-|km|នំប៉ុង}} * {{Z|yai}}: {{W-|yai|нун}} * {{Z|sah}}: {{W-|sah|килиэп}} * {{Z|yi}}: {{W+|yi|ברויט|nt}} * {{Z|esu}}: {{W-|esu|avukaq}}, {{W-|esu|kelipaq}} * {{Z|el}}: {{W+|el|ψωμί|nt}}, {{W+|el|άρτος|n}} *: Kevn: {{W-|grc|ἄρτος|n}}, {{W-|grc|σῖτος|n}} * {{Z|dje}}: {{W-|dje|buru}} * {{Z|za}}: {{W-|za|bouh}} {{werger-bin}} {{werger-ser|xwarin|2}} :→ {{bnr|xwarin}} {{werger-bin}} === Lêker === {{ku-tewîn-lk|nan|form=gerguhêz|niha=n|borî=na}} {{lêker|ku|c=x-gh}} # {{maneid|ku|niyan}} [[niyan]], [[danîn]], [[bi cih kirin]]: #: {{mk|ku|[[pê lê nan]]|[[dewisandin]], [[pê lê kirin]]|birêz=1}} #: {{mk|ku|[[venan]]|bi cih kirin|birêz=1}} # xwe kirin tiştek ku bi rastî wisa be, xwe [[şibandin]], xwe bi awayekî halekî kirin, da ku xelkê [[xapandin|bixapîne]]: #: {{mk|ku|Xwe li mirinî '''nan'''.|Bi hawîyî miriyan kirin|birêz=1}} #: {{mk|ku|Xwe li gêjî '''nan'''.|Bi hawîyî gêjan kirin|birêz=1}} ==== Jê ==== * {{g|ku|pê lê nan}} * {{g|ku|venan}} ==== Agadarî ==== {{agadarî}} Bo agahiyên berfirehtir binêrin: ''{{g|ku|niyan}}''. == {{ziman|ckb|sc=Latn|}} == === Navdêr === {{navdêr|ckb|sc=Latn}} # [[nan#Kurmancî|nan]] # [[xwarin]] === Lêker === {{lêker|ckb|sc=Latn}} # [[nan#Lêker|nan]], [[niyan]], [[danîn]] == {{ziman|zza}} == === Navdêr === {{navdêr|zza|z=n}} # {{g|ku|nan}} ==== Jê ==== {{kol3|zza |nan dayene |nan ra birîyayene |nan û awe |nan û sole |nan vetene |nana binê adirî<q:m> |nanê belxulî<q:n> |nanê belxurî<q:n> |nanê rûnî<q:m> |nanê sacî<q:n> |nanê socî<q:n> |nanê şolmazî<q:n> |nanê taweyî<q:n> |nanê tewqe<q:n> |nanê tîr<q:n> |nanê tîre<q:n> |nanê tîrî<q:n> |nanê veyveyî<q:n> |nanê veyvî<q:n> |nanê xo vetene |nanê . . . vetene |nano anculî<q:n> |nano eşkeba<q:n> |nano eşkeva<q:n> |nano fetir<q:n> |nano fitîl<q:n> |nano fitîr<q:n> |nano huşk<q:n> |nano îştekerde<q:n> |nano kartî<q:n> |nano labaşe<q:n> |nano lawaş<q:n> |nano levaş<q:n> |nano lewaş<q:n> |nano mîrazkerde<q:n> |nano mîşte<q:n> |nano mîştekerde<q:n> |nano onculî<q:n> |nano patîle<q:n> |nano patîre<q:n> |nano wişk<q:n> |nano yewxe<q:n> |nano yowxe<q:n> |nano ziwa<q:n> |nano zuwa<q:n> |nan-awe |nan-sole |nandar |nane-I<q:m> }} == {{ziman|fr}} == === Bilêvkirin === * {{deng|fr|LL-Q150 (fra)-LoquaxFR-nan.wav|Deng|dever=Vosges, Fransa}} * {{deng|fr|LL-Q150 (fra)-WikiLucas00-nan.wav|Deng|dever=Lyon, Fransa}} === Hoker === {{hoker|fr}} # {{f|fr|devkî}} [[na]], [[ne]], [[nexêr]] == {{ziman|gd}} == === Girêdek === {{girêdek|gd}} # [[eger#ku|eger]], [[heke#ku|heke]] == {{ziman|ht}} == === Daçek === {{daçek|ht}} # {{g|ku|di ... de}} === Çavkanî === {{rûpela wergerê|ht|di ... de}} == {{ziman|en}} == === Navdêr === {{navdêr|en}} # [[pîrê]], [[dapîr]] # [[dayen]], [[çavdêr]]a [[zarok]]an # {{f|en|kevnbûyî}} [[xidam]], [[carî]] # {{f|en|kevnbûyî}} [[serejin]], [[mêr]]ê [[jinane]] == {{ziman|ang}} == === Hoker === {{hoker|ang|nān}} # [[ne]], [[na]] === Cînav === {{cînav|ang|nān}} # [[ne]] [[ti]] kes, ne [[çu]] kes == {{ziman|ca}} == === Bilêvkirin === * {{deng|ca|LL-Q7026 (cat)-Marvives-nan.wav|Deng|dever=Barselona, Spanya}} === Navdêr === {{navdêr|ca|z=n}} # [[bejnbost]] == {{ziman|pap}} == === Cînav === {{cînav|pap}} # [[ew#ku|ew]] (pirjimar), [[wan#ku|wan]] == {{ziman|dsb}} == === Navdêr === {{navdêr|dsb|z=n}} # {{f|dsb|malbat}} [[bav#ku|bav]], [[bab#ku|bab]] == {{ziman|hsb}} == === Navdêr === {{navdêr|hsb|z=n}} # {{f|hsb|malbat}} [[bav#ku|bav]], [[bab#ku|bab]] 95u3dryfieb6c4wahy6th21kqhmqjuv 0 10913 6291745 6262405 2026-07-27T23:11:05Z Ghybu 1393 /* Navdêr 1 */ 6291745 wikitext text/x-wiki {{binêre herwiha/de}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{beş|Navdêr 1}} {{deng|ku|LL-Q36163_(kmr)-Key Mîrza-dê.wav|Deng|Wan}} * {{beş|Mane}} {{deng|ku|LL-Q36163_(kmr)-Key Mîrza-dê (hoker).wav|Deng|Wan}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|dê|mê|bang_y=dayê|bang.pj=dayikino}} [[Wêne:Souci maternel.jpg|thumb|Diyek û [[kur]]ê ([[law]]ê) xwe.]] {{navdêr|ku|z=m}} # {{f|ku|malbat}} [[dayik|Dayik]], [[day]], [[deyk]], [[dayk]], [[da]], [[dadê]], [[mak]], [[jin]]a kesek ku jê [[welidîn|welidiye]]. #* {{jêder|ku|jêgirtin=Gava Xezal hate malê '''diya''' xwe maçî kir, rûnişt û nanê xwe xwar."|{{Jêgirtin/Sîma Semend/Xezal/1996}}}} #* {{jêder|ku|jêgirtin=Ger ev '''diya''' min bûya, wê mîna '''dayikan''' bi min re bida û bistanda (...)|{{Jêgirtin/Firat Cewerî/Girtî}}}} ==== Gotinên pêşiyan ==== * [[dê û dotê şer kir, bêaqilan bawer kir]] ==== Bi alfabeyên din ==== * {{ku-ar|دێ}} * {{ku-kr|де}} ==== Tewandî ==== * Gazîkirin: [[dayê]], [[yadê]] * Girêdayî: diya (min, te, wê...) ==== Etîmolojî ==== Ji {{mîr|ine-pro|ku|*dhē(i)-|w=[[mêtin]]}}, hevrehên kurmancî {{q|ku|dayik}}, {{q|ku|dayên}} û {{q|ku|dêl}}, soranî {{g|ckb|دایک|w=dayik}}, {{g|ckb|ده‌ڵ|tr=deł|w=dêl}} û {{g|ckb|دێڵ|tr=dêł|w=dêl}}, hewramî {{g|hac||tr=eḏa|w=dayik}} û {{g|hac||tr=dełe|w=dêl}}, farisî {{g|fa|دایه|tr=dayê|w=[[dayên]]}}, yûnaniya kevn {{g|grc|θηλυς|w=[[mê]]}} û {{g|grc|θήλή|w=[[sermemik]], [[serçiçik]]}}. Heman rehê {{ji|ine-pro|ku|-}} serekaniya peyva {{q|ku|dotin}} ya kurdî ye jî. Bi rêya {{ji|ine-pro|ku|*dʰugh₂tḗr}} belkî ew jî ji {{q|ine-pro|*dhē(i)-}} herwiha hevreha {{q|ku|dot|w=keça kesekî/ê}} ya kurmancî, {{g|fa|دختر|tr=duxter}} ya farisî, {{q|en|daughter}} ya îngilîzî... Bo zêdetir agahiyan li ser wan binere: {{q|ku|dot}}. {{g|ka|დედა|tr=deda|w=dayik}} ya gurcî û {{q|lzz|daduli|w=[[dêl]]}} ya lazî bi ihtimaleke mezin ji zimanên îranî hatine wergirtin. ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W|af|moeder}}, {{W|af|ma}} * {{Z|sq}}: {{W|sq|nënë}} * {{Z|de}}: {{W|de|Mutter}} {{m}} * {{Z|arc}}: {{W-|arc|ܐܡܐ|R=imā}} * {{Z|bm}}: {{W-|bm|bangeba}}, {{W-|bm|woloba}}, {{W-|bm|ba}} * {{Z|eu}}: {{W|eu|ama}} * {{Z|be}}: {{W|be|мати|R=mati}}, {{W|be|маці}} {{m}} * {{Z|br}}: {{W|br|mamm}} * {{Z|bg}}: {{W|bg|майка|R=majka}} * {{Z|cs}}: {{W|cs|matka}} {{m}} * {{Z|zh}}: {{W|zh|母亲|R=mǔqīn}} * {{Z|da}}: {{W|da|moder}}, {{W|da|mor|c}} * {{Z|id}}: {{W|id|ibu}}, {{W|id|bunda}} * {{Z|ar}}: {{W+|ar|أم }} (um) * {{Z|hy}}: {{W|hy|մայր|R=mayr}} * {{Z|eo}}: {{W|eo|patrino}} * {{Z|et}}: {{W|et|ema}} * {{Z|fa}}: {{W|fa|مادر|R=mâdar}}, {{W|fa|والده}} * {{Z|fj}}: {{W|fj|tina}} * {{Z|fi}}: {{W|fi|äiti}} * {{Z|fr}}: {{W|fr|mère}} * {{Z|fy}}: {{W|fy|mem}} {{m}} * {{Z|gd}}: {{W|gd|màthair}} {{m}} * {{Z|ka}}: {{W|ka|დედა|R=deda}} * {{Z|haw}}: {{W-|haw|makuahine}} * {{Z|hi}}: {{W|hi|माँ|R=māṃ}}, {{W|hi|माता}} {{m}} * {{Z|nl}}: {{W|nl|moeder}} {{m}} * {{Z|he}}: {{W|he|אם|tr=em}} * {{Z|io}}: {{W|io|matro}} * {{Z|ig}}: {{W-|ig|nne}} * {{Z|en}}: {{W|en|mother}}, {{W|en|going to}}, {{W|en|matri-}}, {{W|en|female dog|guman=erê}} * {{Z|iu}}: {{W|iu|ᐊᓈᓇ|R=[[anaana]]}} * {{Z|ga}}: {{W|ga|máthair}} {{m}} * {{Z|it}}: {{W|it|madre}} {{m}} * {{Z|is}}: {{W|is|mamma}} {{m}}, {{W|is|móðir}} {{m}} * {{Z|ja}}: {{W|ja|母|R=haha}}, {{W|ja|母親|R=hahaoya}} * {{Z|ca}}: {{W|ca|mare}} {{m}} * {{Z|ko}}: {{W|ko|엄마|R=eomma}}, {{W|ko|어머니|R=oemoeni}} * {{Z|kw}}: {{W|kw|mam}} * {{Z|la}}: {{W|la|mater|cuda=māter}} * {{Z|lv}}: {{W|lv|māte}} {{m}} * {{Z|ln}}: {{W|ln|mamá}} * {{Z|lt}}: {{W|lt|motė}} {{m}}, {{W|lt|motina}} {{m}} * {{Z|lmo}}: {{W-|lmo|mader}} * {{Z|lg}}: {{W-|lg|maama}} * {{Z|lb}}: {{W|lb|Mamm}} {{m}} * {{Z|mk}}: {{W|mk|мајка|R=majkа}} * {{Z|ml}}: {{W|ml|അമ്മ|R=amma}} * {{Z|mt}}: {{W|mt|omm}}, {{W|mt|mamà}}, {{W|mt|ma}} * {{Z|mi}}: {{W|mi|matua}} {{W|mi|wahine}} * {{Z|mr}}: {{W|mr|आई|R=āī}} * {{Z|hu}}: {{W|hu|anya}} * {{Z|xmf}}: {{W-|xmf|დიდა}} * {{Z|egy}}: {{W-|egy|(mwt)}} * {{Z|ne}}: {{W|ne|आम|R=āma}} * {{Z|no}}: {{W|no|mor|c}}, {{W|no|mamma|c}}, {{W|no|moder|c}} * {{Z|oc}}: {{W|oc|maire}} {{m}} * {{Z|ps}}: {{W|ps|مور|R=mwr}} * {{Z|pl}}: {{W|pl|matka}} {{m}}, {{W|pl|mama}} {{m}} * {{Z|pt}}: {{W|pt|mãe}} {{m}} * {{Z|rom}}: {{W-|rom|dej}} {{m}} * {{Z|ro}}: {{W|ro|mamă}} {{m}} * {{Z|ru}}: {{W|ru|мать|R=mat’}} * {{Z|se}}: {{W-|se|eadni}} * {{Z|sa}}: {{W|sa|मातृ|R=mātr̩}} * {{Z|sh}}: {{W|sh|majka}}, {{W|sh|mati}} * {{Z|sh}}: {{W|sh|mat}}, {{W|sh|mati}}, {{W|sh|mater}}, {{W|sh|majka}} {{m}}, {{W|sh|roditeljica}} {{m}}, {{W|sh|rođenica}} {{m}} * {{Z|sco}}: {{W-|sco|mither}}, {{W-|sco|moder}} * {{Z|cu}}: *: krîlî: {{W-|cu|мати|R=mati}} {{m}} *: glagolîtîkî: {{W-|cu|ⰏⰀⰕⰉ|R=mati}} {{m}} * {{Z|sk}}: {{W|sk|matka}} {{m}} * {{Z|sl}}: {{W|sl|mati}} {{m}} * {{Z|ses}}: {{W-|ses|ɲaa}} * {{Z|dsb}}: {{W-|dsb|maś}} {{m}} * {{Z|es}}: {{W|es|madre}} {{m}} * {{Z|sw}}: {{W|sw|mzazi}} * {{Z|sv}}: {{W|sv|mor|c}}, {{W|sv|moder|c}} * {{Z|tl}}: {{W|tl|ina}} * {{Z|ta}}: {{W|ta|தாய்|R=tāy}} * {{Z|th}}: {{W|th|แม่|R=mâe}}, {{W|th|มารดา|R=maandaa}} * {{Z|crh}}: {{W-|crh|ana}} * {{Z|tr}}: {{W|tr|anne}}, {{W|tr|ana}}, {{W|tr|kocakarı}}, {{W|tr|mader}}, {{W|tr|nene}}, {{W|tr|valide}}, {{W|tr|ece|guman=erê}}, {{W|tr|haydi|guman=erê}}, {{W|tr|yallah|guman=erê}}, {{W|tr|cak|guman=erê}} * {{Z|bo}}: {{W-|bo|ཡུམ|R=yum}} * {{Z|tpi}}: {{W|tpi|mama}}, {{W|tpi|mami}} * {{Z|uk}}: {{W|uk|мати|R=máty}} * {{Z|vec}}: {{W|vec|mare}} {{m}}, {{W|vec|mama}} {{m}} * {{Z|vi}}: {{W|vi|mẹ}} * {{Z|cy}}: {{W|cy|mam}} * {{Z|km}}: {{W|km|ម្ដាយ|R=mdai}}, {{W|km|ម៉ែ|R=mai}} * {{Z|grc}}: {{W-|grc|μήτηρ|tr=mếtêr}} * {{Z|el}}: {{W|el|μητέρα|R=mitéra}}, {{W|el|μάνα|R=mána}} * {{Z|zza}}: {{W|zza|ma}} * {{Z|zu}}: {{W|zu|umama}} {{werger-bin}} === Navdêr 2 === {{navdêr|ku|z=n}} # {{maneid|ku|gund}} {{f|ku|kurmanciya rojavayî}} {{g|ku|gund}}, {{g|ku|dih|id=gund}} ==== Bikaranîn ==== Bi taybetî di [[kurmanciya rojavayî]] û di soranî de. ==== Etîmolojî ==== Ji {{ji|ira-pro|ku|*desyu-|w=[[war]]ê dijminan, [[welat]]ê dijminan}}, [[hevreh]]a sanskrîtî {{g|sa||tr=desyu-|w=dijmin}}, avestayî {{g|ae||tr=dexyu-|w=war, welat}}, farisiya kevn {{g|peo||tr=dehyu-}}, pehlewî {{g|pal||tr=dêh}}, [[dih]] ya hin devokên kurmancî (derdorên [[Elbistan]]ê) û navên bajarên [[Dih]] û [[Dihok]]ê ("gundê biçûk"), {{g|ckb|دێ|tr=dê|w=gund}} ya soranî, {{q|zza|dew|tr=gund}} ya zazakî û {{g|fa|ده|tr=dih|w=gund}} ya farisî. ==== Werger ==== {{werger-bnr|gund}} === Pirtik === {{pirtik|ku}} # [[peyvik|Peyvik]]ek [[alîkar]] dikeve gel [[lêker]]ên [[tewandî]] û [[diyar]] dike ku [[bûyer]]ek dê di [[pêşeroj]]ê anku [[dem]]a bêt de [[qewimîn|biqewime]]. #: {{mk|ku|Ez '''dê''' sibê biçim.}} #: {{mk|ku|Ew '''dê''' sala bêt bigihe vir.}} #: {{mk|ku|Dema mezin bibî, '''dê''' ji bîr bikî.}} ==== Hevmane ==== * [[ê]] (2) * [[yê]] (2) * [[wê]] (2) ==== Formên alternatîv ==== * [[dikê]] * [[kê]] ==== Etîmolojî ==== Hevreha zazakî {{q|zza|do}}, ji [[divê]] (bide ber îngilîzî [[will]] = "dê" ji will= vîn, îrade) yan ji "dike" wek "ew dike biçe". ==== Bi zaravayên din ==== * Kurmanciya rojavayî: [[dê]] ** Reşwî: [[dê]] (''hilatî'') ~ [[ê]] ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|werden}} * {{Z|bg}}: {{W+|bg|ще}} * {{Z|my}}: {{W+|my|နောင်}}, {{W+|my|မည်}}, {{W+|my|အံ့}} * {{Z|cs}}: {{l|cs|být}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|會|tr=wui5, wui3}} *: {{Z|cmn}}: {{W+|cmn|將|tr=jiāng}}, {{W+|cmn|要|tr=yào}}, {{W+|cmn|將要|tr=jiāngyào}}, {{W+|cmn|會|tr=huì}} * {{Z|da}}: {{W+|da|vil}}, {{W+|da|skal}} * {{Z|ar}}: {{W+|ar|سَوْفَ}} + ''present tense'', {{W+|ar|سَـ}} + ''present tense'' *: {{W|arz}}: {{W-|arz|ه|cuda=هـ|tr=ha-}} or {{W-|arz|ح|cuda=حـ|tr=ḥa-} *: {{Z|apc}}: {{W-|apc|رح|tr=raḥ}} or {{W-|apc|ح|cuda=حـ|tr=ḥa-}} *: {{Z|ajp}}: {{W-|ajp|رح|tr=raḥ}} or {{W-|ajp|ح|cuda=حـ|tr=ḥa-}} *: {{Z|aeb}}: {{W-|aeb|باش|tr=bēš}} * {{Z|ar}}: {{W-|ar|س-}}, {{W+|ar|سوف}} * {{Z|eo}}: {{W+|eo|-os}} * {{Z|fa}}: {{W+|fa|خواه}} * {{Z|fr}}: {{W-|fr|-erai|cuda=-rai, -ras, -ra, -rons, -rez, -ront}} * {{Z|en}}: {{W+|en|will}}, {{W+|en|going to}} * {{Z|ko}}: {{W-|ko|ᆯ 것이다}}, {{W-|ko|ᆯ게}} * {{Z|bzj}}: {{W-|bzj|wahn}} * {{Z|lo}}: {{W-|lo|ຈະ}}, {{W-|lo|ຈິ}}, {{W-|lo|ຊິ}}, {{W-|lo|ຈັກ}} * {{Z|lb}}: {{W-|lb|wäerten}} * {{Z|mk}}: {{W-|mk|ќе}} * {{Z|ms}}: {{W+|ms|akan}} * {{Z|hu}}: {{W+|hu|fog}} * {{Z|nv}}: {{W-|nv|dooleeł}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|vil}}, {{W-|nb|kommer til å}}, {{W+|nb|skal}} * {{Z|ru}}: {{W+|ru|будет}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хтети}}, {{W-|sh|хтјети}} *: Latînî: {{W-|sh|hteti}}, {{W+|sh|htjeti}} * {{Z|sl}}: {{W+|sl|biti}} * {{Z|es}}: {{W-|es|ir a}} * {{Z|sw}}: {{W-|sw|-ta-}} * {{Z|sv}}: {{W+|sv|ska}} * {{Z|th}}: {{W+|th|จะ}} * {{Z|tr}}: {{W+|tr|-acak}}, {{W+|tr|-ecek}} * {{Z|vi}}: {{W+|vi|sẽ}} * {{Z|km}}: {{W+|km|នឹង}} * {{Z|yap}}: {{W-|yap|ra}} * {{Z|yi}}: {{W-|yi|וועלן}} {{werger-bin}} :{{werger çavkanî|en|will|beş=Ev qismê Wergerê|oldid=75960335}} === Hoker === {{hoker|ku}} # [[de]], [[haydê]], [[yellah]] #: {{mk|ku|'''Dê''' were!}} #: {{mk|ku|'''Dê''' bêje!}} #: {{mk|ku|'''Dê''' bixwin!}} #* {{jêder-kitêb|ku|jêgirtin='''دێ''' کەرەمکەن، شەرم نەکەن، مالا ھەوە یە.|tr='''Dê''' keremken, şerm neken, mala hewe ye.|sc=ku-Arab|sernav=Bêrîvan û Hîvî (Çîrokêt Zarokan)|nivîskar=Leylan Îsmeîl|weşanxane=Çapxana Xanî|cih=Dihok|sal=2012|r=26}} ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|los}}, {{W+|de|dalli}}, {{W-|de|Na kommt!}} * {{Z|zh}}: *: {{Z|cmn}}: {{W-|cmn|快一點|cuda=快一點!|tr=kuài yīdiǎn!}} * {{Z|da}}: {{W-|da|kom nu}} * {{Z|hy}}: {{W-|hy|արագացրու}} * {{Z|fa}}: {{W-|fa|د بیا|tr=de biyâ}}, {{W-|fa|یالّا|tr=yâllâ}}, {{W-|fa|آهان د|tr=âhân de}}, {{W-|fa|بجنب|tr=bejonb}} * {{Z|fi}}: {{W-|fi|[[pitää|pidä]] [[kiire|kiirettä]]}}, {{W+|fi|vauhti|cuda=vauhtia}}, {{W-|fi|hopi hopi}}, {{W-|fi|no niin}} * {{Z|fr}}: {{W+|fr|allez}} * {{Z|nl}}: {{W+|nl|kom op}}, {{W-|nl|vlug een beetje!}}, {{W+|nl|kom aan}} * {{Z|en}}: {{W+|en|come on}}, {{W+|en|hurry up}}, {{W-|en|right,}} (as a 'discourse marker' or interjection), {{W+|en|so}} * {{Z|it}}: {{W+|it|andiamo}} * {{Z|ja}}: {{W+|ja|急ぐ|tr=いそげ, isoge|cuda=急げ|sc=Jpan}}, {{W-|ja|早く|tr=はやく, hayaku|sc=Jpan}} * {{Z|mk}}: {{W-|mk|а́јде}} * {{Z|ms}}: {{W+|ms|mari}}, {{W+|ms|ayuh}} *: {{Z|ms}}: {{W-|ms|ماري}}, {{W-|ms|ايوه}} * {{Z|pt}}: {{W+|pt|vamos!}}, {{W+|pt|anda!}} * {{Z|ro}}: {{W+|ro|haide!}} * {{Z|ru}}: {{W+|ru|айда́!}}, {{W+|ru|пошли́}}, {{W+|ru|пое́хали}}, {{W-|ru|пойдёмте}} * {{Z|sh}}: *: Latînî: {{W+|sh|hajde}} * {{Z|es}}: {{W+|es|¡vamos!}}, {{W+|es|¡andando!}}, {{W+|es|¡órale!}} * {{Z|sv}}: {{W-|sv|kom igen}}, {{W+|sv|skynda}}, {{W+|sv|skynda på}}, {{W-|sv|kom nu}} * {{Z|th}}: {{W-|th|มาเลย|tr=mā ley}} * {{Z|tr}}: {{W+|tr|haydi}}, {{W-|tr|acele et}} * {{Z|vi}}: {{W-|vi|[[mau lên]]}}, {{W-|vi|[[nhanh lên]]}}, {{W-|vi|[[vội lên]]}} * {{Z|el}}: *: Kevn: {{W-|grc|εἶα}} {{werger-bin}} :{{werger çavkanî|en|come on|beş=Ev qismê Wergerê|oldid=76099601}} 7rfviljufr86gbwjln6q2zhrje33r1b 6291752 6291745 2026-07-27T23:17:27Z Ghybu 1393 /* Navdêr 1 */ 6291752 wikitext text/x-wiki {{binêre herwiha/de}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{beş|Navdêr 1}} {{deng|ku|LL-Q36163_(kmr)-Key Mîrza-dê.wav|Deng|Wan}} * {{beş|Mane}} {{deng|ku|LL-Q36163_(kmr)-Key Mîrza-dê (hoker).wav|Deng|Wan}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|dê|mê|bang.yj=dayê|bang.pj=dayikino}} [[Wêne:Souci maternel.jpg|thumb|Diyek û [[kur]]ê ([[law]]ê) xwe.]] {{navdêr|ku|z=m}} # {{f|ku|malbat}} [[dayik|Dayik]], [[day]], [[deyk]], [[dayk]], [[da]], [[dadê]], [[mak]], [[jin]]a kesek ku jê [[welidîn|welidiye]]. #* {{jêder|ku|jêgirtin=Gava Xezal hate malê '''diya''' xwe maçî kir, rûnişt û nanê xwe xwar."|{{Jêgirtin/Sîma Semend/Xezal/1996}}}} #* {{jêder|ku|jêgirtin=Ger ev '''diya''' min bûya, wê mîna '''dayikan''' bi min re bida û bistanda (...)|{{Jêgirtin/Firat Cewerî/Girtî}}}} ==== Gotinên pêşiyan ==== * [[dê û dotê şer kir, bêaqilan bawer kir]] ==== Bi alfabeyên din ==== * {{ku-ar|دێ}} * {{ku-kr|де}} ==== Tewandî ==== * Gazîkirin: [[dayê]], [[yadê]] * Girêdayî: diya (min, te, wê...) ==== Etîmolojî ==== Ji {{mîr|ine-pro|ku|*dhē(i)-|w=[[mêtin]]}}, hevrehên kurmancî {{q|ku|dayik}}, {{q|ku|dayên}} û {{q|ku|dêl}}, soranî {{g|ckb|دایک|w=dayik}}, {{g|ckb|ده‌ڵ|tr=deł|w=dêl}} û {{g|ckb|دێڵ|tr=dêł|w=dêl}}, hewramî {{g|hac||tr=eḏa|w=dayik}} û {{g|hac||tr=dełe|w=dêl}}, farisî {{g|fa|دایه|tr=dayê|w=[[dayên]]}}, yûnaniya kevn {{g|grc|θηλυς|w=[[mê]]}} û {{g|grc|θήλή|w=[[sermemik]], [[serçiçik]]}}. Heman rehê {{ji|ine-pro|ku|-}} serekaniya peyva {{q|ku|dotin}} ya kurdî ye jî. Bi rêya {{ji|ine-pro|ku|*dʰugh₂tḗr}} belkî ew jî ji {{q|ine-pro|*dhē(i)-}} herwiha hevreha {{q|ku|dot|w=keça kesekî/ê}} ya kurmancî, {{g|fa|دختر|tr=duxter}} ya farisî, {{q|en|daughter}} ya îngilîzî... Bo zêdetir agahiyan li ser wan binere: {{q|ku|dot}}. {{g|ka|დედა|tr=deda|w=dayik}} ya gurcî û {{q|lzz|daduli|w=[[dêl]]}} ya lazî bi ihtimaleke mezin ji zimanên îranî hatine wergirtin. ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W|af|moeder}}, {{W|af|ma}} * {{Z|sq}}: {{W|sq|nënë}} * {{Z|de}}: {{W|de|Mutter}} {{m}} * {{Z|arc}}: {{W-|arc|ܐܡܐ|R=imā}} * {{Z|bm}}: {{W-|bm|bangeba}}, {{W-|bm|woloba}}, {{W-|bm|ba}} * {{Z|eu}}: {{W|eu|ama}} * {{Z|be}}: {{W|be|мати|R=mati}}, {{W|be|маці}} {{m}} * {{Z|br}}: {{W|br|mamm}} * {{Z|bg}}: {{W|bg|майка|R=majka}} * {{Z|cs}}: {{W|cs|matka}} {{m}} * {{Z|zh}}: {{W|zh|母亲|R=mǔqīn}} * {{Z|da}}: {{W|da|moder}}, {{W|da|mor|c}} * {{Z|id}}: {{W|id|ibu}}, {{W|id|bunda}} * {{Z|ar}}: {{W+|ar|أم }} (um) * {{Z|hy}}: {{W|hy|մայր|R=mayr}} * {{Z|eo}}: {{W|eo|patrino}} * {{Z|et}}: {{W|et|ema}} * {{Z|fa}}: {{W|fa|مادر|R=mâdar}}, {{W|fa|والده}} * {{Z|fj}}: {{W|fj|tina}} * {{Z|fi}}: {{W|fi|äiti}} * {{Z|fr}}: {{W|fr|mère}} * {{Z|fy}}: {{W|fy|mem}} {{m}} * {{Z|gd}}: {{W|gd|màthair}} {{m}} * {{Z|ka}}: {{W|ka|დედა|R=deda}} * {{Z|haw}}: {{W-|haw|makuahine}} * {{Z|hi}}: {{W|hi|माँ|R=māṃ}}, {{W|hi|माता}} {{m}} * {{Z|nl}}: {{W|nl|moeder}} {{m}} * {{Z|he}}: {{W|he|אם|tr=em}} * {{Z|io}}: {{W|io|matro}} * {{Z|ig}}: {{W-|ig|nne}} * {{Z|en}}: {{W|en|mother}}, {{W|en|going to}}, {{W|en|matri-}}, {{W|en|female dog|guman=erê}} * {{Z|iu}}: {{W|iu|ᐊᓈᓇ|R=[[anaana]]}} * {{Z|ga}}: {{W|ga|máthair}} {{m}} * {{Z|it}}: {{W|it|madre}} {{m}} * {{Z|is}}: {{W|is|mamma}} {{m}}, {{W|is|móðir}} {{m}} * {{Z|ja}}: {{W|ja|母|R=haha}}, {{W|ja|母親|R=hahaoya}} * {{Z|ca}}: {{W|ca|mare}} {{m}} * {{Z|ko}}: {{W|ko|엄마|R=eomma}}, {{W|ko|어머니|R=oemoeni}} * {{Z|kw}}: {{W|kw|mam}} * {{Z|la}}: {{W|la|mater|cuda=māter}} * {{Z|lv}}: {{W|lv|māte}} {{m}} * {{Z|ln}}: {{W|ln|mamá}} * {{Z|lt}}: {{W|lt|motė}} {{m}}, {{W|lt|motina}} {{m}} * {{Z|lmo}}: {{W-|lmo|mader}} * {{Z|lg}}: {{W-|lg|maama}} * {{Z|lb}}: {{W|lb|Mamm}} {{m}} * {{Z|mk}}: {{W|mk|мајка|R=majkа}} * {{Z|ml}}: {{W|ml|അമ്മ|R=amma}} * {{Z|mt}}: {{W|mt|omm}}, {{W|mt|mamà}}, {{W|mt|ma}} * {{Z|mi}}: {{W|mi|matua}} {{W|mi|wahine}} * {{Z|mr}}: {{W|mr|आई|R=āī}} * {{Z|hu}}: {{W|hu|anya}} * {{Z|xmf}}: {{W-|xmf|დიდა}} * {{Z|egy}}: {{W-|egy|(mwt)}} * {{Z|ne}}: {{W|ne|आम|R=āma}} * {{Z|no}}: {{W|no|mor|c}}, {{W|no|mamma|c}}, {{W|no|moder|c}} * {{Z|oc}}: {{W|oc|maire}} {{m}} * {{Z|ps}}: {{W|ps|مور|R=mwr}} * {{Z|pl}}: {{W|pl|matka}} {{m}}, {{W|pl|mama}} {{m}} * {{Z|pt}}: {{W|pt|mãe}} {{m}} * {{Z|rom}}: {{W-|rom|dej}} {{m}} * {{Z|ro}}: {{W|ro|mamă}} {{m}} * {{Z|ru}}: {{W|ru|мать|R=mat’}} * {{Z|se}}: {{W-|se|eadni}} * {{Z|sa}}: {{W|sa|मातृ|R=mātr̩}} * {{Z|sh}}: {{W|sh|majka}}, {{W|sh|mati}} * {{Z|sh}}: {{W|sh|mat}}, {{W|sh|mati}}, {{W|sh|mater}}, {{W|sh|majka}} {{m}}, {{W|sh|roditeljica}} {{m}}, {{W|sh|rođenica}} {{m}} * {{Z|sco}}: {{W-|sco|mither}}, {{W-|sco|moder}} * {{Z|cu}}: *: krîlî: {{W-|cu|мати|R=mati}} {{m}} *: glagolîtîkî: {{W-|cu|ⰏⰀⰕⰉ|R=mati}} {{m}} * {{Z|sk}}: {{W|sk|matka}} {{m}} * {{Z|sl}}: {{W|sl|mati}} {{m}} * {{Z|ses}}: {{W-|ses|ɲaa}} * {{Z|dsb}}: {{W-|dsb|maś}} {{m}} * {{Z|es}}: {{W|es|madre}} {{m}} * {{Z|sw}}: {{W|sw|mzazi}} * {{Z|sv}}: {{W|sv|mor|c}}, {{W|sv|moder|c}} * {{Z|tl}}: {{W|tl|ina}} * {{Z|ta}}: {{W|ta|தாய்|R=tāy}} * {{Z|th}}: {{W|th|แม่|R=mâe}}, {{W|th|มารดา|R=maandaa}} * {{Z|crh}}: {{W-|crh|ana}} * {{Z|tr}}: {{W|tr|anne}}, {{W|tr|ana}}, {{W|tr|kocakarı}}, {{W|tr|mader}}, {{W|tr|nene}}, {{W|tr|valide}}, {{W|tr|ece|guman=erê}}, {{W|tr|haydi|guman=erê}}, {{W|tr|yallah|guman=erê}}, {{W|tr|cak|guman=erê}} * {{Z|bo}}: {{W-|bo|ཡུམ|R=yum}} * {{Z|tpi}}: {{W|tpi|mama}}, {{W|tpi|mami}} * {{Z|uk}}: {{W|uk|мати|R=máty}} * {{Z|vec}}: {{W|vec|mare}} {{m}}, {{W|vec|mama}} {{m}} * {{Z|vi}}: {{W|vi|mẹ}} * {{Z|cy}}: {{W|cy|mam}} * {{Z|km}}: {{W|km|ម្ដាយ|R=mdai}}, {{W|km|ម៉ែ|R=mai}} * {{Z|grc}}: {{W-|grc|μήτηρ|tr=mếtêr}} * {{Z|el}}: {{W|el|μητέρα|R=mitéra}}, {{W|el|μάνα|R=mána}} * {{Z|zza}}: {{W|zza|ma}} * {{Z|zu}}: {{W|zu|umama}} {{werger-bin}} === Navdêr 2 === {{navdêr|ku|z=n}} # {{maneid|ku|gund}} {{f|ku|kurmanciya rojavayî}} {{g|ku|gund}}, {{g|ku|dih|id=gund}} ==== Bikaranîn ==== Bi taybetî di [[kurmanciya rojavayî]] û di soranî de. ==== Etîmolojî ==== Ji {{ji|ira-pro|ku|*desyu-|w=[[war]]ê dijminan, [[welat]]ê dijminan}}, [[hevreh]]a sanskrîtî {{g|sa||tr=desyu-|w=dijmin}}, avestayî {{g|ae||tr=dexyu-|w=war, welat}}, farisiya kevn {{g|peo||tr=dehyu-}}, pehlewî {{g|pal||tr=dêh}}, [[dih]] ya hin devokên kurmancî (derdorên [[Elbistan]]ê) û navên bajarên [[Dih]] û [[Dihok]]ê ("gundê biçûk"), {{g|ckb|دێ|tr=dê|w=gund}} ya soranî, {{q|zza|dew|tr=gund}} ya zazakî û {{g|fa|ده|tr=dih|w=gund}} ya farisî. ==== Werger ==== {{werger-bnr|gund}} === Pirtik === {{pirtik|ku}} # [[peyvik|Peyvik]]ek [[alîkar]] dikeve gel [[lêker]]ên [[tewandî]] û [[diyar]] dike ku [[bûyer]]ek dê di [[pêşeroj]]ê anku [[dem]]a bêt de [[qewimîn|biqewime]]. #: {{mk|ku|Ez '''dê''' sibê biçim.}} #: {{mk|ku|Ew '''dê''' sala bêt bigihe vir.}} #: {{mk|ku|Dema mezin bibî, '''dê''' ji bîr bikî.}} ==== Hevmane ==== * [[ê]] (2) * [[yê]] (2) * [[wê]] (2) ==== Formên alternatîv ==== * [[dikê]] * [[kê]] ==== Etîmolojî ==== Hevreha zazakî {{q|zza|do}}, ji [[divê]] (bide ber îngilîzî [[will]] = "dê" ji will= vîn, îrade) yan ji "dike" wek "ew dike biçe". ==== Bi zaravayên din ==== * Kurmanciya rojavayî: [[dê]] ** Reşwî: [[dê]] (''hilatî'') ~ [[ê]] ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|werden}} * {{Z|bg}}: {{W+|bg|ще}} * {{Z|my}}: {{W+|my|နောင်}}, {{W+|my|မည်}}, {{W+|my|အံ့}} * {{Z|cs}}: {{l|cs|být}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|會|tr=wui5, wui3}} *: {{Z|cmn}}: {{W+|cmn|將|tr=jiāng}}, {{W+|cmn|要|tr=yào}}, {{W+|cmn|將要|tr=jiāngyào}}, {{W+|cmn|會|tr=huì}} * {{Z|da}}: {{W+|da|vil}}, {{W+|da|skal}} * {{Z|ar}}: {{W+|ar|سَوْفَ}} + ''present tense'', {{W+|ar|سَـ}} + ''present tense'' *: {{W|arz}}: {{W-|arz|ه|cuda=هـ|tr=ha-}} or {{W-|arz|ح|cuda=حـ|tr=ḥa-} *: {{Z|apc}}: {{W-|apc|رح|tr=raḥ}} or {{W-|apc|ح|cuda=حـ|tr=ḥa-}} *: {{Z|ajp}}: {{W-|ajp|رح|tr=raḥ}} or {{W-|ajp|ح|cuda=حـ|tr=ḥa-}} *: {{Z|aeb}}: {{W-|aeb|باش|tr=bēš}} * {{Z|ar}}: {{W-|ar|س-}}, {{W+|ar|سوف}} * {{Z|eo}}: {{W+|eo|-os}} * {{Z|fa}}: {{W+|fa|خواه}} * {{Z|fr}}: {{W-|fr|-erai|cuda=-rai, -ras, -ra, -rons, -rez, -ront}} * {{Z|en}}: {{W+|en|will}}, {{W+|en|going to}} * {{Z|ko}}: {{W-|ko|ᆯ 것이다}}, {{W-|ko|ᆯ게}} * {{Z|bzj}}: {{W-|bzj|wahn}} * {{Z|lo}}: {{W-|lo|ຈະ}}, {{W-|lo|ຈິ}}, {{W-|lo|ຊິ}}, {{W-|lo|ຈັກ}} * {{Z|lb}}: {{W-|lb|wäerten}} * {{Z|mk}}: {{W-|mk|ќе}} * {{Z|ms}}: {{W+|ms|akan}} * {{Z|hu}}: {{W+|hu|fog}} * {{Z|nv}}: {{W-|nv|dooleeł}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|vil}}, {{W-|nb|kommer til å}}, {{W+|nb|skal}} * {{Z|ru}}: {{W+|ru|будет}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хтети}}, {{W-|sh|хтјети}} *: Latînî: {{W-|sh|hteti}}, {{W+|sh|htjeti}} * {{Z|sl}}: {{W+|sl|biti}} * {{Z|es}}: {{W-|es|ir a}} * {{Z|sw}}: {{W-|sw|-ta-}} * {{Z|sv}}: {{W+|sv|ska}} * {{Z|th}}: {{W+|th|จะ}} * {{Z|tr}}: {{W+|tr|-acak}}, {{W+|tr|-ecek}} * {{Z|vi}}: {{W+|vi|sẽ}} * {{Z|km}}: {{W+|km|នឹង}} * {{Z|yap}}: {{W-|yap|ra}} * {{Z|yi}}: {{W-|yi|וועלן}} {{werger-bin}} :{{werger çavkanî|en|will|beş=Ev qismê Wergerê|oldid=75960335}} === Hoker === {{hoker|ku}} # [[de]], [[haydê]], [[yellah]] #: {{mk|ku|'''Dê''' were!}} #: {{mk|ku|'''Dê''' bêje!}} #: {{mk|ku|'''Dê''' bixwin!}} #* {{jêder-kitêb|ku|jêgirtin='''دێ''' کەرەمکەن، شەرم نەکەن، مالا ھەوە یە.|tr='''Dê''' keremken, şerm neken, mala hewe ye.|sc=ku-Arab|sernav=Bêrîvan û Hîvî (Çîrokêt Zarokan)|nivîskar=Leylan Îsmeîl|weşanxane=Çapxana Xanî|cih=Dihok|sal=2012|r=26}} ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|los}}, {{W+|de|dalli}}, {{W-|de|Na kommt!}} * {{Z|zh}}: *: {{Z|cmn}}: {{W-|cmn|快一點|cuda=快一點!|tr=kuài yīdiǎn!}} * {{Z|da}}: {{W-|da|kom nu}} * {{Z|hy}}: {{W-|hy|արագացրու}} * {{Z|fa}}: {{W-|fa|د بیا|tr=de biyâ}}, {{W-|fa|یالّا|tr=yâllâ}}, {{W-|fa|آهان د|tr=âhân de}}, {{W-|fa|بجنب|tr=bejonb}} * {{Z|fi}}: {{W-|fi|[[pitää|pidä]] [[kiire|kiirettä]]}}, {{W+|fi|vauhti|cuda=vauhtia}}, {{W-|fi|hopi hopi}}, {{W-|fi|no niin}} * {{Z|fr}}: {{W+|fr|allez}} * {{Z|nl}}: {{W+|nl|kom op}}, {{W-|nl|vlug een beetje!}}, {{W+|nl|kom aan}} * {{Z|en}}: {{W+|en|come on}}, {{W+|en|hurry up}}, {{W-|en|right,}} (as a 'discourse marker' or interjection), {{W+|en|so}} * {{Z|it}}: {{W+|it|andiamo}} * {{Z|ja}}: {{W+|ja|急ぐ|tr=いそげ, isoge|cuda=急げ|sc=Jpan}}, {{W-|ja|早く|tr=はやく, hayaku|sc=Jpan}} * {{Z|mk}}: {{W-|mk|а́јде}} * {{Z|ms}}: {{W+|ms|mari}}, {{W+|ms|ayuh}} *: {{Z|ms}}: {{W-|ms|ماري}}, {{W-|ms|ايوه}} * {{Z|pt}}: {{W+|pt|vamos!}}, {{W+|pt|anda!}} * {{Z|ro}}: {{W+|ro|haide!}} * {{Z|ru}}: {{W+|ru|айда́!}}, {{W+|ru|пошли́}}, {{W+|ru|пое́хали}}, {{W-|ru|пойдёмте}} * {{Z|sh}}: *: Latînî: {{W+|sh|hajde}} * {{Z|es}}: {{W+|es|¡vamos!}}, {{W+|es|¡andando!}}, {{W+|es|¡órale!}} * {{Z|sv}}: {{W-|sv|kom igen}}, {{W+|sv|skynda}}, {{W+|sv|skynda på}}, {{W-|sv|kom nu}} * {{Z|th}}: {{W-|th|มาเลย|tr=mā ley}} * {{Z|tr}}: {{W+|tr|haydi}}, {{W-|tr|acele et}} * {{Z|vi}}: {{W-|vi|[[mau lên]]}}, {{W-|vi|[[nhanh lên]]}}, {{W-|vi|[[vội lên]]}} * {{Z|el}}: *: Kevn: {{W-|grc|εἶα}} {{werger-bin}} :{{werger çavkanî|en|come on|beş=Ev qismê Wergerê|oldid=76099601}} jm1e4d1suud7mspmspvpmf9ja0thljx test 0 12142 6291685 6262755 2026-07-27T18:40:33Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291685 wikitext text/x-wiki {{bnr-h|Test|têst|teşt}} == {{ziman|ku}} == === Bilêvkirin === * {{beş|Navdêr 1}}: {{IPA|ku|/tʰɛst/}}, ته‌ست * {{beş|Navdêr 2}}: {{IPA|ku|/tˤɛst/}}, طه‌ست === Navdêr 1 === {{ku-tewîn-nav|test|mê}} {{navdêr|ku|z=m}} # [[ezmûn]], [[hêçandin]], [[ceribandin]], [[îmtîhan]], [[prove]], [[taqî]], [[cêrribandin]], <br>kirina tiştekê/î daku bêt zanîn ka dê [[biserketî]] be yan na #* {{bêmînak|ku}} ==== Bi alfabeyên din ==== * {{ku-ar|ته‌ست}} ==== Formên alternatîv ==== * {{g|ku|têst}} ==== Bide ber ==== * {{g|ku|tekst}} ==== Jê ==== {{kol3|ku|cure=Jê |test kirin<pos:lêker> |testkirin<pos:navdêr> |testkirî<pos:rengdêr> |testandin |testandî |testî }} ==== Etîmolojî ==== Ji {{deyn|en|ku|test}} (ceribandin) ji fransiya kevn [[test]] (amana ji [[ax]]ê) binêre "test" (2) li jêr. ==== Werger ==== {{werger-ser}} * {{Z|sq}}: {{W+|sq|provë}} (indéfini), {{W-|sq|prova}} (défini) * {{Z|de}}: {{W+|de|Probe}} {{m}} * {{Z|cs}}: {{W+|cs|test}}, {{W+|cs|testování}} * {{Z|zh}}: {{W+|zh|試驗}}, {{W+|zh|试验|R=shìyàn}} * {{Z|ar}}: {{W-|ar|اختبار}} (ixtibar) * {{Z|fa}}: {{W+|fa|آزمایش}} (azmayiş) * {{Z|fi}}: {{W+|fi|koe}} * {{Z|fr}}: [[test]], [[examen]] * {{Z|nl}}: {{W+|nl|test}} {{m}}, {{W+|nl|proef}} {{m}} * {{Z|en}}: {{W+|en|test}} * {{Z|it}}: {{W+|it|prova}}, {{W+|it|verifica}} * {{Z|ja}}: {{W+|ja|実験|R=じっけん, jikken}} * {{Z|ko}}: {{W+|ko|검사|R=geomsa}} * {{Z|hu}}: {{W+|hu|próba}} * {{Z|pt}}: {{W+|pt|teste}} {{n}}, {{W+|pt|prova}} {{Brésil|nocat=1}} * {{Z|ru}}: {{W+|ru|проба}} {{m}}, {{W+|ru|тест}} {{m}} * {{Z|es}}: {{W+|es|prueba}} {{m}} * {{Z|sv}}: {{W+|sv|prov}} {{n}}, {{W+|sv|prövning}} {{c}} * {{Z|tr}}: {{W+|tr|test}}, {{W+|tr|deneme}} {{werger-bin}} ===Navdêr 2 === [[Wêne:1rm60rt0t rtbcwh.jpg|thumb|test (2)]] {{navdêr|ku|z=m}} # [[kuvet]], [[banyo]], [[mencel]], [[legen]], <br>[[aman]]a bê[[qepax]] ya [[pan]] lê ne [[kûr]] ku mirov xwe yan [[cil]]an tê de [[şûştin|dişo]] #* {{bêmînak|ku}} ==== Bi alfabeyên din ==== * {{ku-ar|ته‌ست}}, {{g|ku|sc=Arab|طه‌ست}} ==== Formên alternatîv ==== * {{g|ku|teşt}} ==== Etîmolojî ==== Herwiha {{q|ku|teşt}}, [[hevreh]]a farisî {{g|fa|تشت|tr=teşt}}, erebî {{g|ar|طشت|tr=țeşt}}, ji frensiya kevn {{q|fro|test}} (amana ji [[ax]]ê ji ber ku berê [[cer]] û gelek amanên din ji axê dihatin çêkirin) ji {{ji|la|ku|testum}} (amana ji axê) ji *''terstum'' ([[hişk]]kirî, [[ziwa]]kirî) ji *''tersa'' ([[hişk]] kirin), têkilî [[terra]] ("[[ax]], axa [[ziwa]]", berevajî [[av]]ê ku şil e) ji {{ji|ine-pro|ku|*ters-|w=[[ziwa]], [[hişk]]}} ku herwiha serekaniya peyva [[têhn]] ya kurdî ye. Ji eynî rehê frensiya kevn bi rêya îngilîzî "test" ya bi maneya "azmûn, ceribandin". Herwiha [[tête]] ([[ser]]) ya frensiya niha ji heman rehî ye, pêşî ew bi [[argo]]yî bi maneya "ser" hatiye bikaranîn û taliyê bi temamî cihê "[[chef]]" ya orijînal wergirtiye û "chef" tenê di çend gotinan de [[bisinor]]kirî hiştiye. Peyva "test" ya bi maneya amanekê û "test" ya bi maneya "imtihan"ê ji eynî rehî ne lê li zemanên cuda bi rêya zimanên cuda ketine kurdî. Loma T-ya wan ya destpêkê jî ne wek hev tê gotin: "test"a aman bi T-ya nerm û qelew e, wek "teng" ({{g|ar|ط|tr=-}}), lê "test"a imtihan bi T-ya req anku [[bihilm]] e, wek "tac" ({{g|ar|ت|tr=-}}). ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|Becken}}, {{W+|de|Waschbecken}} * {{Z|eu}}: {{W-|eu|arroa}} * {{Z|br}}: {{W+|br|basin}} * {{Z|bg}}: {{W+|bg|умивалник}} * {{Z|cs}}: {{W-|cs|umyvadlo}} * {{Z|zh}}: {{W+|zh|洗滌槽}}, {{W-|zh|洗涤槽}} * {{Z|da}}: {{W+|da|bassin}} * {{Z|ar}}: {{W-|ar|طشت}} * {{Z|fa}}: {{W+|fa|تشت}} * {{Z|fi}}: {{W+|fi|amme}}, {{W+|fi|pesuallas}} * {{Z|fr}}: {{W+|fr|cuvette}}, {{W+|fr|bassine}}, {{W+|fr|lavabo}} * {{Z|gd}}: {{W-|gd|amar}} * {{Z|ka}}: {{W-|ka|აუზი}} * {{Z|ht}}: {{W-|ht|basin}}, {{W-|ht|basen}} * {{Z|nl}}: {{W+|nl|bassin}} * {{Z|io}}: {{W+|io|baseno}} * {{Z|it}}: {{W+|it|lavandino}}, {{W+|it|lavabo}} * {{Z|ja}}: {{W+|ja|たらい}} * {{Z|ca}}: {{W+|ca|pica}} * {{Z|ky}}: {{W+|ky|миска}}, {{W+|ky|табак}}, {{W+|ky|тепши}}, {{W+|ky|бассейн}}, {{W+|ky|раковина}}, {{W+|ky|көлмө}}, {{W+|ky|резервуар}}, {{W+|ky|ванна}}, {{W+|ky|таз}}, {{W+|ky|дагара}}, {{W+|ky|илеген}}, {{W+|ky|чылапчын}}, {{W+|ky|кудукча}}, {{W+|ky|кудук}}, {{W+|ky|кювета}}, {{W+|ky|котловина}} * {{Z|ko}}: {{W+|ko|대야|tr=daeya}} * {{Z|la}}: {{W-|la|alveus}} * {{Z|mk}}: {{W-|mk|мијалник}}, {{W-|mk|лавабо}} * {{Z|ms}}: {{W-|ms|besen}} * {{Z|mi}}: {{W-|mi|peihana}} * {{Z|no}}: {{W-|no|servant}}, {{W-|no|vaskekum}}, {{W-|no|balje}} * {{Z|pl}}: {{W+|pl|umywalka}} * {{Z|pt}}: {{W+|pt|bacia}}, {{ji|ira-pro||-}} * {{Z|ro}}: {{W+|ro|chiuvetă}} * {{Z|ru}}: {{W+|ru|таз}}, {{W+|ru|умывальник}} * {{Z|es}}: {{W+|es|pileta}}, {{W+|es|lavamanos}} * {{Z|sw}}: {{W+|sw|karai}}, {{W+|sw|beseni}} * {{Z|sv}}: {{W+|sv|tvättfat}}, {{W+|sv|handfat}} * {{Z|tl}}: {{W-|tl|palanggana}} * {{Z|tr}}: {{W+|tr|küvet}} * {{Z|uk}}: {{W-|uk|таз}} * {{Z|vi}}: {{W-|vi|cái chảo}} * {{Z|el}}: {{W+|el|νιπτήρας}} {{werger-bin}} == {{ziman|en}} == === Bilêvkirin === * {{deng|en|en-us-test.ogg|dever=DYA}} * {{deng|en|En-uk-a test.ogg|dever=QY}}verb * {{deng|en|LL-Q1860 (eng)-Nattes à chat-test.wav|Deng|dever=}} * {{deng|en|LL-Q1860 (eng)-Back ache-test.wav|Deng|dever=London, QY}} * {{deng|en|LL-Q1860 (eng)-Vealhurl-test.wav|Deng|dever=Başûrê Îngilistanê, QY}} === Navdêr === {{navdêr|en}} # test, [[azmûn]], [[îmtîhan]] #* {{bêmînak|en}} == {{ziman|hu}} == === Navdêr === {{navdêr|hu}} # {{mijar|hu|anatomî}} {{g|ku|leş}}, {{g|ku|beden}}, {{g|ku|cesed}}, {{g|ku|ten}} #* {{bêmînak|hu}} === Çavkanî === {{rûpela wergerê|hu|leş}} h0kyqfoaa8nyzlqzsxignh0g4nsj8ln têst 0 12143 6291686 5680159 2026-07-27T18:40:51Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291686 wikitext text/x-wiki {{bnr-h|Test|test|teşt}} == {{ziman|ku}} == === Navdêr === {{navdêr|ku|z=-}} # {{guharto|ku|test}} gbdik65xjs2elbqkmkenrf668vkzucx hinav 0 15110 6291651 6282688 2026-07-27T14:23:39Z Keyomerd 8814 /* Etîmolojî */ 6291651 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/hɪˈnɑːv/}} * {{ku-kîte}} === Navdêr === {{navdêr|ku|z=-}} ''bi gelemperî [[pirjimar]] e'' # [[parçe]]yên [[leş]]î yên di [[zik]]î de ango tevahî endamên laşê mirov yên ji [[ûr]] heta [[mîzdank]]ê #* {{bênimûne|ku}} # {{f|ku|mecazî}} [[dil]] û [[ceger]]: #* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Mehbûb û reyhan pir gulav</br>Ker kir li min cerg û '''hinav'''</br>Zehra helahil bû di nav}} ==== Bi alfabeyên din ==== * {{ku-ar|هناڤ}} ==== Formên alternatîv ==== * [[henav]] ==== Jê ==== * [[hinavêş]] * [[hinavêşî]] * [[hinavî]] * [[hinavîn]] * {{mj|Navdêr}} [[hinavçûn]] ==== Etîmolojî ==== Ji {{hv|ine-pro|*sem-||hev-}} + {{g|ine-pro|*dʰeh₁-||danîn}}. Hevreha {{hv|ckb|هەناو}}, {{hv|fa|اندام}}, {{hv|pal|hndʾm}}, {{hv|xpr|sc=Mani|𐫍𐫗𐫅𐫀𐫖}}, {{hv|ae|𐬵𐬀𐬧𐬛𐬁𐬨𐬀}}. Herwiha [[dutayî|dutaya]] [[endam|endamê]] ye. Peyvên {{hv|ar|هِنْدَام}}, {{hv|xcl|անդամ}}, {{hv|myz|ࡄࡀࡍࡃࡀࡌࡀ}}, {{hv|arc|הדמא}}, {{hv|syc|ܗܕܡܐ}} ji zimanên îranî ne. ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|Beuschel|m}} * {{Z|bg}}: {{W+|bg|вътрешности|m-p}} * {{Z|ar}}: {{W-|ar|أحشاء}} * {{Z|fi}}: {{W+|fi|sisälmykset|p}} ; {{W+|fi|sisäelimet|p}} * {{Z|fr}}: {{W+|fr|abbats|n-p}} * {{Z|nl}}: {{W+|nl|ingewanden|p}} * {{Z|en}}: {{W+|en|innards}} * {{Z|lo}}: {{W-|lo|ເຄື່ອງໃນ}} * {{Z|egy}}: {{W-egy|mẖtw|h=m-X:t*w-F51:Z2ss}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|innvoller|n-p}} *: {{Z|nn}}: {{W-|nn|innvolar|n-p}} * {{Z|pl}}: {{W+|pl|bebechy|n-p}} * {{Z|sv}}: {{W+|sv|inälvor|c-p}}, {{W-|sv|inkråm|nt}} * {{Z|shn}}: {{W-|shn|ၶူင်းၼႂ်း}} * {{Z|th}}: {{W+|th|เครื่องใน}} * {{Z|tr}}: {{W-|tr|iç organları}} * Yûnanî: *: Kevn: {{W-|grc|[[σπλάγχνον|σπλάγχνα]]|nt-p}}, {{W-|grc|ἔγκατα|nt-p}} {{werger-bin}} :{{werger çavkanî|en|innards|beş=Ev qismê Wergerê|oldid=75887163}} 4wpv01z45bd9rxc5277oxbrt8p5js2o 6291661 6291651 2026-07-27T15:33:12Z Keyomerd 8814 /* Etîmolojî */ 6291661 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/hɪˈnɑːv/}} * {{ku-kîte}} === Navdêr === {{navdêr|ku|z=-}} ''bi gelemperî [[pirjimar]] e'' # [[parçe]]yên [[leş]]î yên di [[zik]]î de ango tevahî endamên laşê mirov yên ji [[ûr]] heta [[mîzdank]]ê #* {{bênimûne|ku}} # {{f|ku|mecazî}} [[dil]] û [[ceger]]: #* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Mehbûb û reyhan pir gulav</br>Ker kir li min cerg û '''hinav'''</br>Zehra helahil bû di nav}} ==== Bi alfabeyên din ==== * {{ku-ar|هناڤ}} ==== Formên alternatîv ==== * [[henav]] ==== Jê ==== * [[hinavêş]] * [[hinavêşî]] * [[hinavî]] * [[hinavîn]] * {{mj|Navdêr}} [[hinavçûn]] ==== Etîmolojî ==== Ji {{hv|ine-pro|*sem-||hev-}} + {{g|ine-pro|*dʰeh₁-||danîn}}. Hevreha {{hv|ckb|هەناو}}, {{hv|fa|اندام}}, {{hv|pal|hndʾm}}, {{hv|xpr|sc=Mani|𐫍𐫗𐫅𐫀𐫖}}, {{hv|ae|𐬵𐬀𐬧𐬛𐬁𐬨𐬀}}. Herwiha {{cotreh|ku|endam|hûr=1}} ye. Peyvên {{hv|ar|هِنْدَام}}, {{hv|xcl|անդամ}}, {{hv|myz|ࡄࡀࡍࡃࡀࡌࡀ}}, {{hv|arc|הדמא}}, {{hv|syc|ܗܕܡܐ}} ji zimanên îranî ne. ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|Beuschel|m}} * {{Z|bg}}: {{W+|bg|вътрешности|m-p}} * {{Z|ar}}: {{W-|ar|أحشاء}} * {{Z|fi}}: {{W+|fi|sisälmykset|p}} ; {{W+|fi|sisäelimet|p}} * {{Z|fr}}: {{W+|fr|abbats|n-p}} * {{Z|nl}}: {{W+|nl|ingewanden|p}} * {{Z|en}}: {{W+|en|innards}} * {{Z|lo}}: {{W-|lo|ເຄື່ອງໃນ}} * {{Z|egy}}: {{W-egy|mẖtw|h=m-X:t*w-F51:Z2ss}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|innvoller|n-p}} *: {{Z|nn}}: {{W-|nn|innvolar|n-p}} * {{Z|pl}}: {{W+|pl|bebechy|n-p}} * {{Z|sv}}: {{W+|sv|inälvor|c-p}}, {{W-|sv|inkråm|nt}} * {{Z|shn}}: {{W-|shn|ၶူင်းၼႂ်း}} * {{Z|th}}: {{W+|th|เครื่องใน}} * {{Z|tr}}: {{W-|tr|iç organları}} * Yûnanî: *: Kevn: {{W-|grc|[[σπλάγχνον|σπλάγχνα]]|nt-p}}, {{W-|grc|ἔγκατα|nt-p}} {{werger-bin}} :{{werger çavkanî|en|innards|beş=Ev qismê Wergerê|oldid=75887163}} 9uqlw7byxkxgyh1kiogbt4whfutocnt 6291663 6291661 2026-07-27T15:55:07Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291663 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/hɪˈnɑːv/}} * {{ku-kîte}} === Navdêr === {{navdêr|ku|z=-}} ''bi gelemperî [[pirjimar]] e'' # [[parçe]]yên [[leş]]î yên di [[zik]]î de ango tevahî endamên laşê mirov yên ji [[ûr]] heta [[mîzdank]]ê #* {{bênimûne|ku}} # {{f|ku|mecazî}} [[dil]] û [[ceger]] #* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Mehbûb û reyhan pir gulav</br>Ker kir li min cerg û '''hinav'''</br>Zehra helahil bû di nav}} ==== Bi alfabeyên din ==== * {{ku-ar|هناڤ}} ==== Formên alternatîv ==== * [[henav]] ==== Jê ==== * [[hinavêş]] * [[hinavêşî]] * [[hinavî]] * [[hinavîn]] * {{mj|Navdêr}} [[hinavçûn]] ==== Etîmolojî ==== Ji {{hv|ine-pro|*sem-||hev-}} + {{g|ine-pro|*dʰeh₁-||danîn}}. Hevreha {{hv|ckb|هەناو}}, {{hv|fa|اندام}}, {{hv|pal|hndʾm}}, {{hv|xpr|sc=Mani|𐫍𐫗𐫅𐫀𐫖}}, {{hv|ae|𐬵𐬀𐬧𐬛𐬁𐬨𐬀}}. Herwiha {{cotreh|ku|endam|hûr=1}} ye. Peyvên {{hv|ar|هِنْدَام}}, {{hv|xcl|անդամ}}, {{hv|myz|ࡄࡀࡍࡃࡀࡌࡀ}}, {{hv|arc|הדמא}}, {{hv|syc|ܗܕܡܐ}} ji zimanên îranî ne. ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|Beuschel|m}} * {{Z|bg}}: {{W+|bg|вътрешности|m-p}} * {{Z|ar}}: {{W-|ar|أحشاء}} * {{Z|fi}}: {{W+|fi|sisälmykset|p}} ; {{W+|fi|sisäelimet|p}} * {{Z|fr}}: {{W+|fr|abbats|n-p}} * {{Z|nl}}: {{W+|nl|ingewanden|p}} * {{Z|en}}: {{W+|en|innards}} * {{Z|lo}}: {{W-|lo|ເຄື່ອງໃນ}} * {{Z|egy}}: {{W-egy|mẖtw|h=m-X:t*w-F51:Z2ss}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|innvoller|n-p}} *: {{Z|nn}}: {{W-|nn|innvolar|n-p}} * {{Z|pl}}: {{W+|pl|bebechy|n-p}} * {{Z|sv}}: {{W+|sv|inälvor|c-p}}, {{W-|sv|inkråm|nt}} * {{Z|shn}}: {{W-|shn|ၶူင်းၼႂ်း}} * {{Z|th}}: {{W+|th|เครื่องใน}} * {{Z|tr}}: {{W-|tr|iç organları}} * Yûnanî: *: Kevn: {{W-|grc|[[σπλάγχνον|σπλάγχνα]]|nt-p}}, {{W-|grc|ἔγκατα|nt-p}} {{werger-bin}} :{{werger çavkanî|en|innards|beş=Ev qismê Wergerê|oldid=75887163}} he9xxig9oo6yf3f5zdhattyfk7c2a9s 0 20523 6291690 6231894 2026-07-27T19:14:59Z Ghybu 1393 /* Navdêr 1 */ 6291690 wikitext text/x-wiki {{bnr-h|as|As}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|aş|nêr|çemandî_y=aş'''î''';'''ê'''ş}} [[Wêne:Argenstein water mill.jpg|thumb|Aşek]] {{navdêr|ku|z=n}} # [[amûr|Amûrek]] e pê [[genim]] têt [[hêran]] daku bibe [[ar]] (bi [[hêz]]a [[av]]ê yan [[ba]]yî [[xebitîn|dixebite]]). #* {{jêder|ku|{{Jêgirtin/Ehmedê Xanî/Mem û Zîn}}|jêgirtin=Fi'lê di Bekir meger nizanîn<br />Em qismê emîr qismê '''aş''' în<br />Pirfetl û ger în û pêş û paş în}} #* {{jêder|ku|2=1947, Ereb Şemo, Şivanê Kurd|jêgirtin=Bavo, ku genim ji xwediyê dewaran distand bi pişta xwe dibire '''êş'''.}} ==== Bi alfabeyên din ==== * {{ku-ar|ئاش}} * {{ku-kr|аш}} ==== Nêzîk ==== * [[destar]] ==== Pîrepend==== * An naçe aşî, an diçe aşvanî dikuje * Derdê qeraşî her av biçe aşî ==== Têkildar ==== * [[banger]] ==== Jê ==== {{stûn| * [[aşî]] * [[aşkar]] * [[aşkarî]] * [[aşxane]] * [[aşkarîtî]] * [[aşkartî]] * [[aşvan]] * [[aşvanî]] * [[aşvanîtî]] * [[aşvantî]] * {{mj|Lêker}} [[aş bûn]] * {{mj|Lêker}} [[aş kirin]] * {{mj|Navdêr}} [[aşbûn]] * {{mj|Navdêr}} [[aşkirin]] * {{mj|Rengdêr}} [[aşbûyî]] * {{mj|Rengdêr}} [[aşkirî]] }} ==== Etîmolojî ==== [[hevreh|Hevreha]] soranî {{g|ckb|ئاش}}, {{q|ku|asaw|w="aş-av" = aşê avê}}, farisî {{g|fa|آسیاب|tr=asyab, as-y-ab|w=aşê avê}}, zazakî {{q|zza|ayre}} / {{q|zza|arê}}, avestayî {{g|ae|𐬀𐬯𐬏𐬭𐬀‎|tr=asūra|w=tûj}}, latviyayî {{q|lv|ass|w=tûj}} û {{q|lv|ašs|w=lezgîn}}, yûnaniya kevn {{g|grc|ὀξύς|w=tûj}}, ingilîzî {{g|en|edge|w=kinar}}... {{ji|ine-pro|ku|*h₂eḱ-|w=tûj}}. Bo guherîna dengê ş/s bi farisî û zimanên kurdî binêre paş û {{g|fa|پس}}(pes). ==== Werger ==== {{werger-ser}} * {{Z|ady}}: {{W-|ady|шъхьалы}} * {{Z|sq}}: {{W-|sq|thyese|m}}, {{W+|sq|mulli|n}} * {{Z|goh}}: {{W-|goh|mulin|m}} * {{Z|de}}: {{W+|de|Mühle|m}}, {{W+|de|Mahlwerk|nt}} *: {{Z|pdc}}: {{W-|pdc|Miehl|m}} * {{Z|zgh}}: {{W-|zgh|ⴰⵣⵔⴳ|n|tr=azrg}}, {{W-|zgh|ⴰⵣⵔⴳ ⵏ ⵡⴰⵎⴰⵏ|n|tr=azrg n waman}} * {{Z|arc}}: *: {{Z|syc}}: {{W-|syc|ܪܚܝܐ|m|tr=raḥyā}} *: {{Z|he}}: {{W-|arc|רחיא|m|tr=raḥyā}} * {{Z|rup}}: {{W-|rup|moarã|m}} * {{Z|ast}}: {{W+|ast|molín|n}} * {{Z|av}}: {{W-|av|гьобо}} * {{Z|az}}: {{W+|az|dəyirman}} * {{Z|eu}}: {{W+|eu|errota}}, {{W+|eu|eihera}} * {{Z|ba}}: {{W-|ba|тирмән|sc=Cyrl}} * {{Z|be}}: {{W-|be|млын|n}} * {{Z|bn}}: * {{Z|br}}: {{W+|br|milin|m}} * {{Z|bg}}: {{W+|bg|ме́лница|m}} * {{Z|my}}: * {{Z|bua}}: {{W-|bua|тээрмэ}} * {{Z|ce}}: {{W-|ce|хьера}} * {{Z|cs}}: {{W+|cs|mlýn|n}} * {{Z|chr}}: {{W-|chr|ᏍᏙᏍᎩᏱ}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|磨坊|tr=mo6 fong1}}, {{W-|yue|粉碎機|tr=fan2 seoi3 gei1}} *: {{Z|hak}}: {{W-|hak|磨坊|tr=mò-fòng}} *: {{Z|cmn}}: {{W+|cmn|磨坊|tr=mòfāng}}, {{W+|cmn|磨機|tr=mójī}}, {{W-|cmn|粉碎機|tr=fěnsuìjī}} *: {{Z|nan}}: {{W-|nan|磨坊|tr=bō-hng}} * {{Z|cv}}: {{W-|cv|арман|sc=Cyrl}} * {{Z|da}}: {{W+|da|mølle|g}} * {{Z|dar}}: {{W-|dar|шинкьа}} * {{Z|id}}: {{W+|id|kincir}} * {{Z|ar}}: {{W-|ar|مَطْحَنَة|m}} *: {{Z|ary}}: {{W-|ary|رحى|m|tr=rḥā}} * {{Z|hy}}: {{W+|hy|աղաց}}, {{W+|hy|ջրաղաց}} * {{Z|myv}}: {{W-|myv|ведьгев}} * {{Z|eo}}: {{W-|eo|muelilo}} * {{Z|et}}: {{W-|et|veski}} * {{Z|fa}}: {{W+|fa|آسیا|tr=âsyâ}}, {{W+|fa|آس|tr=âs}}, {{W-|fa|آسیو|tr=âsiyow}} * {{Z|fo}}: {{W-|fo|mylla|m}}, {{W-|fo|mylna|m}} * {{Z|fi}}: {{W+|fi|mylly}} * {{Z|fr}}: {{W+|fr|moulin|n}} * {{Z|fur}}: {{W-|fur|mulìn|n}}, {{W-|fur|mulin|n}} * {{Z|fy}}: {{W-|fy|mûne|g}} * {{Z|gd}}: {{W-|gd|muileann|n|m}} * {{Z|gl}}: {{W+|gl|muíño|n}} * {{Z|ka}}: {{W+|ka|წისქვილი}} * {{Z|ht}}: {{W-|ht|moulen}} * {{Z|hi}}: {{W+|hi|चक्की|m}} * {{Z|nl}}: {{W+|nl|molen|n}} * {{Z|hrx}}: {{W-|hrx|Mihl|m}} * {{Z|he}}: {{W+|he|טַחֲנָה|m|tr=takhánah}} * {{Z|io}}: {{W+|io|muelilo}} * {{Z|enm}}: {{W-|enm|mylne}} * {{Z|en}}: {{W+|en|mill}} (gringding aparatus) * {{Z|inh}}: {{W-|inh|хьайра}} * {{Z|ga}}: {{W-|ga|muileann|n}} * {{Z|it}}: {{W+|it|mulino|n}}, {{W+|it|macinatoio|n}}, {{W+|it|mola|m}}, {{W+|it|macina|m}} * {{Z|gmq-jmk}}: {{W-|gmq-jmk|kvæðn|m}} * {{Z|ja}}: {{W-|ja|粉砕機|tr=ふんさいき, funsaiki}}, {{W-|ja|ミル|tr=miru}}, {{W-|ja|製粉所|tr=せいふんじょ, seifunjo}} * {{Z|csb}}: {{W-|csb|młin|n}} * {{Z|ca}}: {{W+|ca|molí|n}} * {{Z|ky}}: {{W+|ky|тегирмен|sc=Cyrl}} * {{Z|ko}}: {{W+|ko|방아}}, {{W+|ko|방앗간}}, {{W-|ko|제분소(製粉所)}} * {{Z|kw}}: {{W-|kw|melin|m}} * {{Z|lbe}}: {{W-|lbe|гьарахъалу}} * {{Z|lkt}}: {{W-|lkt|onákpaŋ}} * {{Z|la}}: {{W-|la|mola}} * {{Z|lv}}: {{W-|lv|malējs}} * {{Z|lo}}: {{W-|lo|ໂຮງສີ}} * {{Z|lez}}: {{W-|lez|регьв}} * {{Z|lt}}: {{W+|lt|malūnas|n}} * {{Z|lb}}: {{W-|lb|Millen|m}} * {{Z|mhn}}: {{W-|mhn|mil|m}} * {{Z|mk}}: {{W-|mk|млин|n}}, {{W-|mk|ме́лница|m}} * {{Z|mg}}: {{W+|mg|bakaka}} * {{Z|gv}}: {{W-|gv|mwyllin|m}} * {{Z|mi}}: {{W-|mi|mira}} * {{Z|hu}}: {{W+|hu|daráló}}, {{W+|hu|őrlő}}, {{W-|hu|passzírozó}} * {{Z|mdf}}: {{W-|mdf|ведькев}} * Mongolî: {{W+|mn|тээрэм}} * {{Z|no}}: *: {{Z|nb}}: {{W+|no|mølle|n|m}} *: {{Z|nn}}: {{W-|nn|mylne|m}}, {{W+|no|mølle|m}} * {{Z|oc}}: {{W+|oc|molin|n}} * {{Z|os}}: {{W-|os|куырой|sc=Cyrl}} * {{Z|ota}}: {{W-|ota|دگرمن|tr=değirmen}}, {{W-|ota|آسیا|tr=asya}}, {{W-|ota|رحی|tr=raha}} * {{Z|ug}}: {{W-|ug|تۈگمەن}} * {{Z|uz}}: {{W+|uz|tegirmon}} * {{Z|ps}}: {{W+|ps|ژرنده|n|tr=žranda}} * {{Z|pl}}: {{W+|pl|młyn|m-in}} * {{Z|pt}}: {{W-|pt|moenda|m}}, {{W+|pt|moinho|n}} * {{Z|kk}}: {{W-|kk|диірмен|sc=Cyrl}} * {{Z|rgn}}: {{W-|rgn|mulén|n}} * {{Z|rm}}: {{W-|rm|mulin|n}}, {{W-|rm|mulegn|n}} * {{Z|rom}}: {{W-|rom|asiav|n}} * {{Z|ro}}: {{W+|ro|moară}} * {{Z|ru}}: {{W+|ru|ме́льница|m}}, {{W+|ru|дроби́лка|m}} * Samî: *: {{Z|smn}}: {{W-|smn|millo}} *: {{Z|se}}: {{W-|se|millu}} * {{Z|sc}}: {{W-|sc|molinu}}, {{W-|sc|mulinu}} * {{Z|scn}}: {{W+|scn|mulinu|n}} * {{Z|srn}}: {{W-|srn|miri}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|млин|n|sc=Cyrl}} *: Latînî: {{W+|sh|mlin|n}} * {{Z|sk}}: {{W-|sk|mlyn|n}} * {{Z|sl}}: {{W+|sl|mlin|n}} * {{Z|es}}: {{W+|es|molino|n}} * {{Z|sv}}: {{W+|sv|kvarn|g}}, {{W+|sv|mölla|g}} * {{Z|sn}}: {{W-|sn|chigayo|c7}} * {{Z|cjs}}: {{W-|cjs|тербен|tr=terben}} * {{Z|tg}}: {{W-|tg|осиё|sc=Cyrl}}, {{W-|tg|осиёб|sc=Cyrl}} * {{Z|th}}: {{W-|th|โรงสี}} * {{Z|te}}: {{W+|te|గానుగ}} * {{Z|crh}}: {{W-|crh|degirmen}}, {{W-|crh|termen}} * {{Z|tt}}: {{W+|tt|тегермән|sc=Cyrl}} * {{Z|tr}}: {{W+|tr|değirmen}} * {{Z|tk}}: {{W-|tk|degirmen}} * {{Z|trw}}: {{W-|trw|ژان|tr=žān}} * {{Z|tn}}: {{W-|tn|tshilô|c9}} * {{Z|udm}}: {{W-|udm|вуко}} * {{Z|ur}}: {{W-|ur|چَکّی|m|tr=cakkī}} * {{Z|uk}}: {{W-|uk|млин|n}} * {{Z|vec}}: {{W-|vec|molin|n}}, {{W-|vec|mulin|n}}, {{W-|vec|mułin|n}} * {{Z|vi}}: {{W+|vi|cối xay}} * {{Z|wa}}: {{W+|wa|molén|n}} * {{Z|war}}: {{W-|war|gilingan}} * {{Z|cy}}: {{W+|cy|melin|m}} * {{Z|wym}}: {{W-|wym|mejł|m}} * {{Z|kjh}}: {{W-|kjh|тербен}} * {{Z|km}}: {{W-|km|ម៉ាស៊ីនកិនស្រូវ}} * {{Z|sah}}: {{W-|sah|миэлиҥсэ}} * {{Z|yi}}: {{W-|yi|מיל|m}} * {{Z|el}}: {{W+|el|μύλος|n}}, {{W-|el|αλεστική μηχανή|m}} *: {{Z|grc}}: {{W-|grc|μύλη|m}} {{werger-bin}} === Navdêr 2 === {{navdêr|ku|z=m}} # [[şorbe]], [[girarşîr]] #* {{bêmînak|ku}} # [[xwarin]], [[zad]] #* {{bêmînak|ku}} ==== Bikaranîn ==== Di kurdî de tenê wek [[pêşgir]]ekê tê bikaranîn, ne wek peyveke serbixwe. ==== Jê ==== * [[aşpêj]] * [[aşpêjgeh]] * [[aşpêjî]] * [[aşpêjxane]] ==== Etîmolojî ==== Ji yan [[hevreh]]a farisî {{g|fa|آش|tr=aş}}, herdu ihtimalen ji zimanekî [[tirkîkî]], bo nimûne ji {{deyn|az|ku|aş}}, [[hevreh]]a tirkî {{q|tr|aş}}, başkîrî {{g|ba|аш|tr=aş}} û yakûtî {{g|sah|ас|tr=as}}. Carinan tê idiakirin ku [[hevreh]]a sanskrîtî {{g|sa|आश|tr=āśa}} ye lê li gor dîroka dengnasiyê ev ne mimkin e. ==== Werger ==== {{werger-ser}} {{werger-bin}} === Rengdêr === {{rengdêr|ku}} # {{guherto|aşt}} == {{ziman|tr}} == === Bilêvkirin === * {{deng|tr|LL-Q256 (tur)-Veravi95-aş.wav|Deng|dever=}} === Navdêr === {{navdêr|tr}} # aş, [[xwarin]] #* {{bêmînak|tr}} 52u06uk28t9h136olic1fu8armaxeq3 6291691 6291690 2026-07-27T19:20:08Z Wikihez 7344 /* Jê */ 6291691 wikitext text/x-wiki {{bnr-h|as|As}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|aş|nêr|çemandî_y=aş'''î''';'''ê'''ş}} [[Wêne:Argenstein water mill.jpg|thumb|Aşek]] {{navdêr|ku|z=n}} # [[amûr|Amûrek]] e pê [[genim]] têt [[hêran]] daku bibe [[ar]] (bi [[hêz]]a [[av]]ê yan [[ba]]yî [[xebitîn|dixebite]]). #* {{jêder|ku|{{Jêgirtin/Ehmedê Xanî/Mem û Zîn}}|jêgirtin=Fi'lê di Bekir meger nizanîn<br />Em qismê emîr qismê '''aş''' în<br />Pirfetl û ger în û pêş û paş în}} #* {{jêder|ku|2=1947, Ereb Şemo, Şivanê Kurd|jêgirtin=Bavo, ku genim ji xwediyê dewaran distand bi pişta xwe dibire '''êş'''.}} ==== Bi alfabeyên din ==== * {{ku-ar|ئاش}} * {{ku-kr|аш}} ==== Nêzîk ==== * [[destar]] ==== Pîrepend==== * An naçe aşî, an diçe aşvanî dikuje * Derdê qeraşî her av biçe aşî ==== Têkildar ==== * [[banger]] ==== Jê ==== {{kol3|ku|cure=Jê |aşî |aşkar |aşkarî |aşxane |aşkarîtî |aşkartî |aşvan |aşvanî |aşvanîtî |aşvantî |aş bûn<q:lêker> |aş kirin<q:lêker> |aşbûn<q:navdêr> |aşkirin<q:navdêr> |aşbûyî<q:rengdêr> |aşkirî<q:rengdêr> }} ==== Etîmolojî ==== [[hevreh|Hevreha]] soranî {{g|ckb|ئاش}}, {{q|ku|asaw|w="aş-av" = aşê avê}}, farisî {{g|fa|آسیاب|tr=asyab, as-y-ab|w=aşê avê}}, zazakî {{q|zza|ayre}} / {{q|zza|arê}}, avestayî {{g|ae|𐬀𐬯𐬏𐬭𐬀‎|tr=asūra|w=tûj}}, latviyayî {{q|lv|ass|w=tûj}} û {{q|lv|ašs|w=lezgîn}}, yûnaniya kevn {{g|grc|ὀξύς|w=tûj}}, ingilîzî {{g|en|edge|w=kinar}}... {{ji|ine-pro|ku|*h₂eḱ-|w=tûj}}. Bo guherîna dengê ş/s bi farisî û zimanên kurdî binêre paş û {{g|fa|پس}}(pes). ==== Werger ==== {{werger-ser}} * {{Z|ady}}: {{W-|ady|шъхьалы}} * {{Z|sq}}: {{W-|sq|thyese|m}}, {{W+|sq|mulli|n}} * {{Z|goh}}: {{W-|goh|mulin|m}} * {{Z|de}}: {{W+|de|Mühle|m}}, {{W+|de|Mahlwerk|nt}} *: {{Z|pdc}}: {{W-|pdc|Miehl|m}} * {{Z|zgh}}: {{W-|zgh|ⴰⵣⵔⴳ|n|tr=azrg}}, {{W-|zgh|ⴰⵣⵔⴳ ⵏ ⵡⴰⵎⴰⵏ|n|tr=azrg n waman}} * {{Z|arc}}: *: {{Z|syc}}: {{W-|syc|ܪܚܝܐ|m|tr=raḥyā}} *: {{Z|he}}: {{W-|arc|רחיא|m|tr=raḥyā}} * {{Z|rup}}: {{W-|rup|moarã|m}} * {{Z|ast}}: {{W+|ast|molín|n}} * {{Z|av}}: {{W-|av|гьобо}} * {{Z|az}}: {{W+|az|dəyirman}} * {{Z|eu}}: {{W+|eu|errota}}, {{W+|eu|eihera}} * {{Z|ba}}: {{W-|ba|тирмән|sc=Cyrl}} * {{Z|be}}: {{W-|be|млын|n}} * {{Z|bn}}: * {{Z|br}}: {{W+|br|milin|m}} * {{Z|bg}}: {{W+|bg|ме́лница|m}} * {{Z|my}}: * {{Z|bua}}: {{W-|bua|тээрмэ}} * {{Z|ce}}: {{W-|ce|хьера}} * {{Z|cs}}: {{W+|cs|mlýn|n}} * {{Z|chr}}: {{W-|chr|ᏍᏙᏍᎩᏱ}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|磨坊|tr=mo6 fong1}}, {{W-|yue|粉碎機|tr=fan2 seoi3 gei1}} *: {{Z|hak}}: {{W-|hak|磨坊|tr=mò-fòng}} *: {{Z|cmn}}: {{W+|cmn|磨坊|tr=mòfāng}}, {{W+|cmn|磨機|tr=mójī}}, {{W-|cmn|粉碎機|tr=fěnsuìjī}} *: {{Z|nan}}: {{W-|nan|磨坊|tr=bō-hng}} * {{Z|cv}}: {{W-|cv|арман|sc=Cyrl}} * {{Z|da}}: {{W+|da|mølle|g}} * {{Z|dar}}: {{W-|dar|шинкьа}} * {{Z|id}}: {{W+|id|kincir}} * {{Z|ar}}: {{W-|ar|مَطْحَنَة|m}} *: {{Z|ary}}: {{W-|ary|رحى|m|tr=rḥā}} * {{Z|hy}}: {{W+|hy|աղաց}}, {{W+|hy|ջրաղաց}} * {{Z|myv}}: {{W-|myv|ведьгев}} * {{Z|eo}}: {{W-|eo|muelilo}} * {{Z|et}}: {{W-|et|veski}} * {{Z|fa}}: {{W+|fa|آسیا|tr=âsyâ}}, {{W+|fa|آس|tr=âs}}, {{W-|fa|آسیو|tr=âsiyow}} * {{Z|fo}}: {{W-|fo|mylla|m}}, {{W-|fo|mylna|m}} * {{Z|fi}}: {{W+|fi|mylly}} * {{Z|fr}}: {{W+|fr|moulin|n}} * {{Z|fur}}: {{W-|fur|mulìn|n}}, {{W-|fur|mulin|n}} * {{Z|fy}}: {{W-|fy|mûne|g}} * {{Z|gd}}: {{W-|gd|muileann|n|m}} * {{Z|gl}}: {{W+|gl|muíño|n}} * {{Z|ka}}: {{W+|ka|წისქვილი}} * {{Z|ht}}: {{W-|ht|moulen}} * {{Z|hi}}: {{W+|hi|चक्की|m}} * {{Z|nl}}: {{W+|nl|molen|n}} * {{Z|hrx}}: {{W-|hrx|Mihl|m}} * {{Z|he}}: {{W+|he|טַחֲנָה|m|tr=takhánah}} * {{Z|io}}: {{W+|io|muelilo}} * {{Z|enm}}: {{W-|enm|mylne}} * {{Z|en}}: {{W+|en|mill}} (gringding aparatus) * {{Z|inh}}: {{W-|inh|хьайра}} * {{Z|ga}}: {{W-|ga|muileann|n}} * {{Z|it}}: {{W+|it|mulino|n}}, {{W+|it|macinatoio|n}}, {{W+|it|mola|m}}, {{W+|it|macina|m}} * {{Z|gmq-jmk}}: {{W-|gmq-jmk|kvæðn|m}} * {{Z|ja}}: {{W-|ja|粉砕機|tr=ふんさいき, funsaiki}}, {{W-|ja|ミル|tr=miru}}, {{W-|ja|製粉所|tr=せいふんじょ, seifunjo}} * {{Z|csb}}: {{W-|csb|młin|n}} * {{Z|ca}}: {{W+|ca|molí|n}} * {{Z|ky}}: {{W+|ky|тегирмен|sc=Cyrl}} * {{Z|ko}}: {{W+|ko|방아}}, {{W+|ko|방앗간}}, {{W-|ko|제분소(製粉所)}} * {{Z|kw}}: {{W-|kw|melin|m}} * {{Z|lbe}}: {{W-|lbe|гьарахъалу}} * {{Z|lkt}}: {{W-|lkt|onákpaŋ}} * {{Z|la}}: {{W-|la|mola}} * {{Z|lv}}: {{W-|lv|malējs}} * {{Z|lo}}: {{W-|lo|ໂຮງສີ}} * {{Z|lez}}: {{W-|lez|регьв}} * {{Z|lt}}: {{W+|lt|malūnas|n}} * {{Z|lb}}: {{W-|lb|Millen|m}} * {{Z|mhn}}: {{W-|mhn|mil|m}} * {{Z|mk}}: {{W-|mk|млин|n}}, {{W-|mk|ме́лница|m}} * {{Z|mg}}: {{W+|mg|bakaka}} * {{Z|gv}}: {{W-|gv|mwyllin|m}} * {{Z|mi}}: {{W-|mi|mira}} * {{Z|hu}}: {{W+|hu|daráló}}, {{W+|hu|őrlő}}, {{W-|hu|passzírozó}} * {{Z|mdf}}: {{W-|mdf|ведькев}} * Mongolî: {{W+|mn|тээрэм}} * {{Z|no}}: *: {{Z|nb}}: {{W+|no|mølle|n|m}} *: {{Z|nn}}: {{W-|nn|mylne|m}}, {{W+|no|mølle|m}} * {{Z|oc}}: {{W+|oc|molin|n}} * {{Z|os}}: {{W-|os|куырой|sc=Cyrl}} * {{Z|ota}}: {{W-|ota|دگرمن|tr=değirmen}}, {{W-|ota|آسیا|tr=asya}}, {{W-|ota|رحی|tr=raha}} * {{Z|ug}}: {{W-|ug|تۈگمەن}} * {{Z|uz}}: {{W+|uz|tegirmon}} * {{Z|ps}}: {{W+|ps|ژرنده|n|tr=žranda}} * {{Z|pl}}: {{W+|pl|młyn|m-in}} * {{Z|pt}}: {{W-|pt|moenda|m}}, {{W+|pt|moinho|n}} * {{Z|kk}}: {{W-|kk|диірмен|sc=Cyrl}} * {{Z|rgn}}: {{W-|rgn|mulén|n}} * {{Z|rm}}: {{W-|rm|mulin|n}}, {{W-|rm|mulegn|n}} * {{Z|rom}}: {{W-|rom|asiav|n}} * {{Z|ro}}: {{W+|ro|moară}} * {{Z|ru}}: {{W+|ru|ме́льница|m}}, {{W+|ru|дроби́лка|m}} * Samî: *: {{Z|smn}}: {{W-|smn|millo}} *: {{Z|se}}: {{W-|se|millu}} * {{Z|sc}}: {{W-|sc|molinu}}, {{W-|sc|mulinu}} * {{Z|scn}}: {{W+|scn|mulinu|n}} * {{Z|srn}}: {{W-|srn|miri}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|млин|n|sc=Cyrl}} *: Latînî: {{W+|sh|mlin|n}} * {{Z|sk}}: {{W-|sk|mlyn|n}} * {{Z|sl}}: {{W+|sl|mlin|n}} * {{Z|es}}: {{W+|es|molino|n}} * {{Z|sv}}: {{W+|sv|kvarn|g}}, {{W+|sv|mölla|g}} * {{Z|sn}}: {{W-|sn|chigayo|c7}} * {{Z|cjs}}: {{W-|cjs|тербен|tr=terben}} * {{Z|tg}}: {{W-|tg|осиё|sc=Cyrl}}, {{W-|tg|осиёб|sc=Cyrl}} * {{Z|th}}: {{W-|th|โรงสี}} * {{Z|te}}: {{W+|te|గానుగ}} * {{Z|crh}}: {{W-|crh|degirmen}}, {{W-|crh|termen}} * {{Z|tt}}: {{W+|tt|тегермән|sc=Cyrl}} * {{Z|tr}}: {{W+|tr|değirmen}} * {{Z|tk}}: {{W-|tk|degirmen}} * {{Z|trw}}: {{W-|trw|ژان|tr=žān}} * {{Z|tn}}: {{W-|tn|tshilô|c9}} * {{Z|udm}}: {{W-|udm|вуко}} * {{Z|ur}}: {{W-|ur|چَکّی|m|tr=cakkī}} * {{Z|uk}}: {{W-|uk|млин|n}} * {{Z|vec}}: {{W-|vec|molin|n}}, {{W-|vec|mulin|n}}, {{W-|vec|mułin|n}} * {{Z|vi}}: {{W+|vi|cối xay}} * {{Z|wa}}: {{W+|wa|molén|n}} * {{Z|war}}: {{W-|war|gilingan}} * {{Z|cy}}: {{W+|cy|melin|m}} * {{Z|wym}}: {{W-|wym|mejł|m}} * {{Z|kjh}}: {{W-|kjh|тербен}} * {{Z|km}}: {{W-|km|ម៉ាស៊ីនកិនស្រូវ}} * {{Z|sah}}: {{W-|sah|миэлиҥсэ}} * {{Z|yi}}: {{W-|yi|מיל|m}} * {{Z|el}}: {{W+|el|μύλος|n}}, {{W-|el|αλεστική μηχανή|m}} *: {{Z|grc}}: {{W-|grc|μύλη|m}} {{werger-bin}} === Navdêr 2 === {{navdêr|ku|z=m}} # [[şorbe]], [[girarşîr]] #* {{bêmînak|ku}} # [[xwarin]], [[zad]] #* {{bêmînak|ku}} ==== Bikaranîn ==== Di kurdî de tenê wek [[pêşgir]]ekê tê bikaranîn, ne wek peyveke serbixwe. ==== Jê ==== * [[aşpêj]] * [[aşpêjgeh]] * [[aşpêjî]] * [[aşpêjxane]] ==== Etîmolojî ==== Ji yan [[hevreh]]a farisî {{g|fa|آش|tr=aş}}, herdu ihtimalen ji zimanekî [[tirkîkî]], bo nimûne ji {{deyn|az|ku|aş}}, [[hevreh]]a tirkî {{q|tr|aş}}, başkîrî {{g|ba|аш|tr=aş}} û yakûtî {{g|sah|ас|tr=as}}. Carinan tê idiakirin ku [[hevreh]]a sanskrîtî {{g|sa|आश|tr=āśa}} ye lê li gor dîroka dengnasiyê ev ne mimkin e. ==== Werger ==== {{werger-ser}} {{werger-bin}} === Rengdêr === {{rengdêr|ku}} # {{guherto|aşt}} == {{ziman|tr}} == === Bilêvkirin === * {{deng|tr|LL-Q256 (tur)-Veravi95-aş.wav|Deng|dever=}} === Navdêr === {{navdêr|tr}} # aş, [[xwarin]] #* {{bêmînak|tr}} glhr2use00htpeuaryrlak3cu5ndkrt 6291742 6291691 2026-07-27T23:10:01Z Ghybu 1393 /* Navdêr 1 */ 6291742 wikitext text/x-wiki {{bnr-h|as|As}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr 1 === {{ku-tewîn-nav|aş|nêr|alt.çem.yj='''ê'''ş}} [[Wêne:Argenstein water mill.jpg|thumb|Aşek]] {{navdêr|ku|z=n}} # [[amûr|Amûrek]] e pê [[genim]] têt [[hêran]] daku bibe [[ar]] (bi [[hêz]]a [[av]]ê yan [[ba]]yî [[xebitîn|dixebite]]). #* {{jêder|ku|{{Jêgirtin/Ehmedê Xanî/Mem û Zîn}}|jêgirtin=Fi'lê di Bekir meger nizanîn<br />Em qismê emîr qismê '''aş''' în<br />Pirfetl û ger în û pêş û paş în}} #* {{jêder|ku|2=1947, Ereb Şemo, Şivanê Kurd|jêgirtin=Bavo, ku genim ji xwediyê dewaran distand bi pişta xwe dibire '''êş'''.}} ==== Bi alfabeyên din ==== * {{ku-ar|ئاش}} * {{ku-kr|аш}} ==== Nêzîk ==== * [[destar]] ==== Pîrepend==== * An naçe aşî, an diçe aşvanî dikuje * Derdê qeraşî her av biçe aşî ==== Têkildar ==== * [[banger]] ==== Jê ==== {{kol3|ku|cure=Jê |aşî |aşkar |aşkarî |aşxane |aşkarîtî |aşkartî |aşvan |aşvanî |aşvanîtî |aşvantî |aş bûn<q:lêker> |aş kirin<q:lêker> |aşbûn<q:navdêr> |aşkirin<q:navdêr> |aşbûyî<q:rengdêr> |aşkirî<q:rengdêr> }} ==== Etîmolojî ==== [[hevreh|Hevreha]] soranî {{g|ckb|ئاش}}, {{q|ku|asaw|w="aş-av" = aşê avê}}, farisî {{g|fa|آسیاب|tr=asyab, as-y-ab|w=aşê avê}}, zazakî {{q|zza|ayre}} / {{q|zza|arê}}, avestayî {{g|ae|𐬀𐬯𐬏𐬭𐬀‎|tr=asūra|w=tûj}}, latviyayî {{q|lv|ass|w=tûj}} û {{q|lv|ašs|w=lezgîn}}, yûnaniya kevn {{g|grc|ὀξύς|w=tûj}}, ingilîzî {{g|en|edge|w=kinar}}... {{ji|ine-pro|ku|*h₂eḱ-|w=tûj}}. Bo guherîna dengê ş/s bi farisî û zimanên kurdî binêre paş û {{g|fa|پس}}(pes). ==== Werger ==== {{werger-ser}} * {{Z|ady}}: {{W-|ady|шъхьалы}} * {{Z|sq}}: {{W-|sq|thyese|m}}, {{W+|sq|mulli|n}} * {{Z|goh}}: {{W-|goh|mulin|m}} * {{Z|de}}: {{W+|de|Mühle|m}}, {{W+|de|Mahlwerk|nt}} *: {{Z|pdc}}: {{W-|pdc|Miehl|m}} * {{Z|zgh}}: {{W-|zgh|ⴰⵣⵔⴳ|n|tr=azrg}}, {{W-|zgh|ⴰⵣⵔⴳ ⵏ ⵡⴰⵎⴰⵏ|n|tr=azrg n waman}} * {{Z|arc}}: *: {{Z|syc}}: {{W-|syc|ܪܚܝܐ|m|tr=raḥyā}} *: {{Z|he}}: {{W-|arc|רחיא|m|tr=raḥyā}} * {{Z|rup}}: {{W-|rup|moarã|m}} * {{Z|ast}}: {{W+|ast|molín|n}} * {{Z|av}}: {{W-|av|гьобо}} * {{Z|az}}: {{W+|az|dəyirman}} * {{Z|eu}}: {{W+|eu|errota}}, {{W+|eu|eihera}} * {{Z|ba}}: {{W-|ba|тирмән|sc=Cyrl}} * {{Z|be}}: {{W-|be|млын|n}} * {{Z|bn}}: * {{Z|br}}: {{W+|br|milin|m}} * {{Z|bg}}: {{W+|bg|ме́лница|m}} * {{Z|my}}: * {{Z|bua}}: {{W-|bua|тээрмэ}} * {{Z|ce}}: {{W-|ce|хьера}} * {{Z|cs}}: {{W+|cs|mlýn|n}} * {{Z|chr}}: {{W-|chr|ᏍᏙᏍᎩᏱ}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|磨坊|tr=mo6 fong1}}, {{W-|yue|粉碎機|tr=fan2 seoi3 gei1}} *: {{Z|hak}}: {{W-|hak|磨坊|tr=mò-fòng}} *: {{Z|cmn}}: {{W+|cmn|磨坊|tr=mòfāng}}, {{W+|cmn|磨機|tr=mójī}}, {{W-|cmn|粉碎機|tr=fěnsuìjī}} *: {{Z|nan}}: {{W-|nan|磨坊|tr=bō-hng}} * {{Z|cv}}: {{W-|cv|арман|sc=Cyrl}} * {{Z|da}}: {{W+|da|mølle|g}} * {{Z|dar}}: {{W-|dar|шинкьа}} * {{Z|id}}: {{W+|id|kincir}} * {{Z|ar}}: {{W-|ar|مَطْحَنَة|m}} *: {{Z|ary}}: {{W-|ary|رحى|m|tr=rḥā}} * {{Z|hy}}: {{W+|hy|աղաց}}, {{W+|hy|ջրաղաց}} * {{Z|myv}}: {{W-|myv|ведьгев}} * {{Z|eo}}: {{W-|eo|muelilo}} * {{Z|et}}: {{W-|et|veski}} * {{Z|fa}}: {{W+|fa|آسیا|tr=âsyâ}}, {{W+|fa|آس|tr=âs}}, {{W-|fa|آسیو|tr=âsiyow}} * {{Z|fo}}: {{W-|fo|mylla|m}}, {{W-|fo|mylna|m}} * {{Z|fi}}: {{W+|fi|mylly}} * {{Z|fr}}: {{W+|fr|moulin|n}} * {{Z|fur}}: {{W-|fur|mulìn|n}}, {{W-|fur|mulin|n}} * {{Z|fy}}: {{W-|fy|mûne|g}} * {{Z|gd}}: {{W-|gd|muileann|n|m}} * {{Z|gl}}: {{W+|gl|muíño|n}} * {{Z|ka}}: {{W+|ka|წისქვილი}} * {{Z|ht}}: {{W-|ht|moulen}} * {{Z|hi}}: {{W+|hi|चक्की|m}} * {{Z|nl}}: {{W+|nl|molen|n}} * {{Z|hrx}}: {{W-|hrx|Mihl|m}} * {{Z|he}}: {{W+|he|טַחֲנָה|m|tr=takhánah}} * {{Z|io}}: {{W+|io|muelilo}} * {{Z|enm}}: {{W-|enm|mylne}} * {{Z|en}}: {{W+|en|mill}} (gringding aparatus) * {{Z|inh}}: {{W-|inh|хьайра}} * {{Z|ga}}: {{W-|ga|muileann|n}} * {{Z|it}}: {{W+|it|mulino|n}}, {{W+|it|macinatoio|n}}, {{W+|it|mola|m}}, {{W+|it|macina|m}} * {{Z|gmq-jmk}}: {{W-|gmq-jmk|kvæðn|m}} * {{Z|ja}}: {{W-|ja|粉砕機|tr=ふんさいき, funsaiki}}, {{W-|ja|ミル|tr=miru}}, {{W-|ja|製粉所|tr=せいふんじょ, seifunjo}} * {{Z|csb}}: {{W-|csb|młin|n}} * {{Z|ca}}: {{W+|ca|molí|n}} * {{Z|ky}}: {{W+|ky|тегирмен|sc=Cyrl}} * {{Z|ko}}: {{W+|ko|방아}}, {{W+|ko|방앗간}}, {{W-|ko|제분소(製粉所)}} * {{Z|kw}}: {{W-|kw|melin|m}} * {{Z|lbe}}: {{W-|lbe|гьарахъалу}} * {{Z|lkt}}: {{W-|lkt|onákpaŋ}} * {{Z|la}}: {{W-|la|mola}} * {{Z|lv}}: {{W-|lv|malējs}} * {{Z|lo}}: {{W-|lo|ໂຮງສີ}} * {{Z|lez}}: {{W-|lez|регьв}} * {{Z|lt}}: {{W+|lt|malūnas|n}} * {{Z|lb}}: {{W-|lb|Millen|m}} * {{Z|mhn}}: {{W-|mhn|mil|m}} * {{Z|mk}}: {{W-|mk|млин|n}}, {{W-|mk|ме́лница|m}} * {{Z|mg}}: {{W+|mg|bakaka}} * {{Z|gv}}: {{W-|gv|mwyllin|m}} * {{Z|mi}}: {{W-|mi|mira}} * {{Z|hu}}: {{W+|hu|daráló}}, {{W+|hu|őrlő}}, {{W-|hu|passzírozó}} * {{Z|mdf}}: {{W-|mdf|ведькев}} * Mongolî: {{W+|mn|тээрэм}} * {{Z|no}}: *: {{Z|nb}}: {{W+|no|mølle|n|m}} *: {{Z|nn}}: {{W-|nn|mylne|m}}, {{W+|no|mølle|m}} * {{Z|oc}}: {{W+|oc|molin|n}} * {{Z|os}}: {{W-|os|куырой|sc=Cyrl}} * {{Z|ota}}: {{W-|ota|دگرمن|tr=değirmen}}, {{W-|ota|آسیا|tr=asya}}, {{W-|ota|رحی|tr=raha}} * {{Z|ug}}: {{W-|ug|تۈگمەن}} * {{Z|uz}}: {{W+|uz|tegirmon}} * {{Z|ps}}: {{W+|ps|ژرنده|n|tr=žranda}} * {{Z|pl}}: {{W+|pl|młyn|m-in}} * {{Z|pt}}: {{W-|pt|moenda|m}}, {{W+|pt|moinho|n}} * {{Z|kk}}: {{W-|kk|диірмен|sc=Cyrl}} * {{Z|rgn}}: {{W-|rgn|mulén|n}} * {{Z|rm}}: {{W-|rm|mulin|n}}, {{W-|rm|mulegn|n}} * {{Z|rom}}: {{W-|rom|asiav|n}} * {{Z|ro}}: {{W+|ro|moară}} * {{Z|ru}}: {{W+|ru|ме́льница|m}}, {{W+|ru|дроби́лка|m}} * Samî: *: {{Z|smn}}: {{W-|smn|millo}} *: {{Z|se}}: {{W-|se|millu}} * {{Z|sc}}: {{W-|sc|molinu}}, {{W-|sc|mulinu}} * {{Z|scn}}: {{W+|scn|mulinu|n}} * {{Z|srn}}: {{W-|srn|miri}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|млин|n|sc=Cyrl}} *: Latînî: {{W+|sh|mlin|n}} * {{Z|sk}}: {{W-|sk|mlyn|n}} * {{Z|sl}}: {{W+|sl|mlin|n}} * {{Z|es}}: {{W+|es|molino|n}} * {{Z|sv}}: {{W+|sv|kvarn|g}}, {{W+|sv|mölla|g}} * {{Z|sn}}: {{W-|sn|chigayo|c7}} * {{Z|cjs}}: {{W-|cjs|тербен|tr=terben}} * {{Z|tg}}: {{W-|tg|осиё|sc=Cyrl}}, {{W-|tg|осиёб|sc=Cyrl}} * {{Z|th}}: {{W-|th|โรงสี}} * {{Z|te}}: {{W+|te|గానుగ}} * {{Z|crh}}: {{W-|crh|degirmen}}, {{W-|crh|termen}} * {{Z|tt}}: {{W+|tt|тегермән|sc=Cyrl}} * {{Z|tr}}: {{W+|tr|değirmen}} * {{Z|tk}}: {{W-|tk|degirmen}} * {{Z|trw}}: {{W-|trw|ژان|tr=žān}} * {{Z|tn}}: {{W-|tn|tshilô|c9}} * {{Z|udm}}: {{W-|udm|вуко}} * {{Z|ur}}: {{W-|ur|چَکّی|m|tr=cakkī}} * {{Z|uk}}: {{W-|uk|млин|n}} * {{Z|vec}}: {{W-|vec|molin|n}}, {{W-|vec|mulin|n}}, {{W-|vec|mułin|n}} * {{Z|vi}}: {{W+|vi|cối xay}} * {{Z|wa}}: {{W+|wa|molén|n}} * {{Z|war}}: {{W-|war|gilingan}} * {{Z|cy}}: {{W+|cy|melin|m}} * {{Z|wym}}: {{W-|wym|mejł|m}} * {{Z|kjh}}: {{W-|kjh|тербен}} * {{Z|km}}: {{W-|km|ម៉ាស៊ីនកិនស្រូវ}} * {{Z|sah}}: {{W-|sah|миэлиҥсэ}} * {{Z|yi}}: {{W-|yi|מיל|m}} * {{Z|el}}: {{W+|el|μύλος|n}}, {{W-|el|αλεστική μηχανή|m}} *: {{Z|grc}}: {{W-|grc|μύλη|m}} {{werger-bin}} === Navdêr 2 === {{navdêr|ku|z=m}} # [[şorbe]], [[girarşîr]] #* {{bêmînak|ku}} # [[xwarin]], [[zad]] #* {{bêmînak|ku}} ==== Bikaranîn ==== Di kurdî de tenê wek [[pêşgir]]ekê tê bikaranîn, ne wek peyveke serbixwe. ==== Jê ==== * [[aşpêj]] * [[aşpêjgeh]] * [[aşpêjî]] * [[aşpêjxane]] ==== Etîmolojî ==== Ji yan [[hevreh]]a farisî {{g|fa|آش|tr=aş}}, herdu ihtimalen ji zimanekî [[tirkîkî]], bo nimûne ji {{deyn|az|ku|aş}}, [[hevreh]]a tirkî {{q|tr|aş}}, başkîrî {{g|ba|аш|tr=aş}} û yakûtî {{g|sah|ас|tr=as}}. Carinan tê idiakirin ku [[hevreh]]a sanskrîtî {{g|sa|आश|tr=āśa}} ye lê li gor dîroka dengnasiyê ev ne mimkin e. ==== Werger ==== {{werger-ser}} {{werger-bin}} === Rengdêr === {{rengdêr|ku}} # {{guherto|aşt}} == {{ziman|tr}} == === Bilêvkirin === * {{deng|tr|LL-Q256 (tur)-Veravi95-aş.wav|Deng|dever=}} === Navdêr === {{navdêr|tr}} # aş, [[xwarin]] #* {{bêmînak|tr}} if1y2h3y4fh80z0z2xnb0cku9nd186x ard 0 20532 6291741 6236824 2026-07-27T23:09:18Z Ghybu 1393 /* Navdêr */ 6291741 wikitext text/x-wiki {{ds|ard|ar}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{deng|ku|LL-Q36163 (kmr)-Ebulfîda-ard.wav|Deng|Bidlîs}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|ard|nêr|alt.çem.yj='''ê'''rd}} [[Wêne:Flour 06.jpg|thumb|Ard]] {{navdêr|ku|z=n}} # {{f|ku|xwarin}} [[ar|Ar]], [[toz]]a [[hevîr]] jê têt çêkirin. #: {{mk|ku|Aş '''êrd''' dihêre.}} #* {{bêmînak|ku}} ==== Hevmane ==== * [[arvan]] ==== Etîmolojî ==== Bi pehlewî {{g|pal||tr=ārd}} bû, bi soranî, kelhûrî, hewramî û zazaki {{q|zza|ard}} e, di hinek zaravayên kurmancî de pîta [[d]]'yê winda dike. Lê rastnivîsa xwe disa jî dibê "ard" be. ==== Werger ==== {{werger-ser}} * {{Z|ady}}: {{W-|ady|хьаджыгъэ}} * {{Z|af}}: {{W+|af|meel}} * {{Z|sq}}: {{W+|sq|miell|n}} * {{Z|de}}: {{W+|de|Mehl|nt}} * {{Z|alt}}: {{W-|alt|кулур}}, {{W-|alt|ун}} * {{Z|am}}: {{W-|am|ዱቄት}} * {{Z|as}}: {{W-|as|আটা}} * {{Z|ast}}: {{W-|ast|fariña|m}}, {{W-|ast|farina|m}} * {{Z|ain}}: {{W-|ain|アマㇺコホ|tr=amamkoho}} * {{Z|az}}: {{W+|az|un}} * {{Z|eu}}: {{W-|eu|irin}} * {{Z|ba}}: {{W-|ba|он}} * {{Z|bbl}}: {{W-|bbl|ჰ̡აჲრუ̆}}, {{W-|bbl|ჰ̡აჲრი̆}} * {{Z|be}}: {{W-|be|мука́|m}} * {{Z|bal}}: {{W-|bal|آڑت|tr=ářt}} * {{Z|bn}}: {{W+|bn|আটা}}, {{W-|bn|ময়দা}} * {{Z|br}}: {{W+|br|bleud|n}} * {{Z|kxd}}: {{W-|kxd|tapung}} * {{Z|bg}}: {{W+|bg|брашно́|nt}} * {{Z|my}}: {{W+|my|မှုန့်}}, {{W+|my|ဂျုံမှုန့်}} * {{Z|bua}}: {{W-|bua|гурил}} * {{Z|cs}}: {{W+|cs|mouka|m}} * {{Z|chr}}: {{W-|chr|ᎢᏌ}}, {{W-|chr|ᎤᏣᎴᏍᏓ}}, {{W-|chr|ᎢᏒ ᏩᏂᎨ}} * {{Z|ny}}: {{W-|ny|ufa}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|麵粉|tr=min6 fan2}} *: {{Z|cmn}}: {{W+|cmn|麵粉|tr=miànfěn}} * {{Z|cv}}: {{W-|cv|ҫӑнӑх}} * {{Z|dlm}}: {{W-|dlm|faraina|m}} * {{Z|da}}: {{W+|da|mel|nt}} * {{Z|dta}}: {{W-|dta|golii}} * {{Z|sce}}: {{W-|sce|ghurun}} * {{Z|egl}}: {{W-|egl|faréṅna|m}} * {{Z|id}}: {{W+|id|tepung}} * {{Z|ar}}: {{W-|ar|طَحِين|n}}, {{W+|ar|دَقِيق|n}} *: {{Z|acw}}: {{W-|acw|دَقيق|n|tr=dagīg}} *: {{Z|ary}}: {{W-|ary|دجيج|n|tr=dgig}}, {{W-|ary|طحين|n|tr=ṭḥin}} * {{Z|hy}}: {{W+|hy|ալյուր}} *: {{Z|xcl}}: {{W-|xcl|ալիւր}} * {{Z|eo}}: {{W+|eo|faruno}} * {{Z|et}}: {{W-|et|jahu}} * {{Z|evn}}: {{W-|evn|бурдук}} * {{Z|fax}}: {{W-|fax|fariña|m}} * {{Z|fa}}: {{W+|fa|آرد|tr=ârd}} * {{Z|fo}}: {{W-|fo|mjøl|nt}} * {{Z|fi}}: {{W+|fi|jauho}} * {{Z|fr}}: {{W+|fr|farine|m}} * {{Z|fur}}: {{W-|fur|farine|m}} * {{Z|stq}}: {{W-|stq|Meel}} * {{Z|fy}}: {{W-|fy|moal}} * {{Z|gd}}: {{W-|gd|flùr|n}}, {{W-|gd|min|m}} * {{Z|gl}}: {{W+|gl|fariña|m}}, {{W-|gl|óleo|n}} * {{Z|gu}}: {{W-|gu|આટો|n}}, {{W-|gu|લોટ|n}} * {{Z|ka}}: {{W-|ka|ფქვილი}} * {{Z|ht}}: {{W-|ht|farin}} * {{Z|hi}}: {{W+|hi|आटा|n}} * {{Z|nl}}: {{W+|nl|meel|nt}}, {{W+|nl|bloem|m}} * {{Z|he}}: {{W+|he|קֶמַח|n|tr=kemakh}} * {{Z|io}}: {{W+|io|farino}} * {{Z|ang}}: {{W-|ang|melu|nt}} * {{Z|enm}}: {{W-|enm|flour}}, {{W-|enm|mele}} * {{Z|en}}: {{W+|en|flour}} * {{Z|ia}}: {{W-|ia|farina}} * {{Z|ga}}: {{W-|ga|plúr|n}} *: {{Z|sga}}: {{W-|sga|men}} * {{Z|ist}}: {{W-|ist|fareîna|m}} * {{Z|it}}: {{W+|it|farina|m}} * {{Z|is}}: {{W+|is|mjöl|nt}} * {{Z|ja}}: {{W+|ja|穀粉|tr=こくふん, kokufun}}, {{W+|ja|小麦粉|tr=こむぎこ, komugi-ko}}, {{W+|ja|メリケン粉|tr=めりけんこ, meriken-ko}} * {{Z|kaw}}: {{W-|kaw|gĕlĕpung}} * {{Z|jv}}: {{W+|jv|glepung}} * {{Z|kbd}}: {{W-|kbd|хьэжыгъэ}} * {{Z|kl}}: {{W-|kl|qajuusat}} * {{Z|xal}}: {{W-|xal|һуйр}} * {{Z|kn}}: {{W+|kn|ಹಿಟ್ಟು}} * {{Z|ca}}: {{W+|ca|farina|m}} * {{Z|kgp}}: {{W-|kgp|farĩnh}} * {{Z|qu}}: {{W-|qu|ullpu}}, {{W-|qu|haku}}, {{W-|qu|kuta}} * {{Z|ky}}: {{W+|ky|ун}} * {{Z|si}}: {{W-|si|පිටි}} * {{Z|rw}}: {{W-|rw|ifu}} * {{Z|koi}}: {{W-|koi|пызь}} * {{Z|swb}}: {{W-|swb|ngano|c9|c10}} * {{Z|ko}}: {{W+|ko|밀가루}}, {{W+|ko|가루}} * {{Z|kw}}: {{W-|kw|bleus|n}} * {{Z|co}}: {{W+|co|farina|m}} * {{Z|kmv}}: {{W-|kmv|fahin}} * {{Z|pov}}: {{W-|pov|forinha}} * {{Z|vkp}}: {{W-|vkp|fari}} * {{Z|mcm}}: {{W-|mcm|farinya}} * {{Z|kum}}: {{W-|kum|ун}} * {{Z|lad}}: {{W-|lad|farina|m}} * {{Z|la}}: {{W-|la|farīna|m}} * {{Z|lv}}: {{W+|lv|milti|m-p}} * {{Z|lo}}: {{W-|lo|ແປ້ງ}} * {{Z|lzz}}: {{W-|lzz|ქუერი}} * {{Z|lij}}: {{W-|lij|faænn-a|m}} * {{Z|lt}}: {{W+|lt|miltai|m-p}} * {{Z|lmo}}: {{W-|lmo|farinna|m}} * {{Z|lb}}: {{W-|lb|Miel|nt}} * {{Z|mdh}}: {{W-|mdh|tapung}} * {{Z|mk}}: {{W-|mk|брашно|nt}} * {{Z|mg}}: {{W+|mg|koba}} * {{Z|ml}}: {{W-|ml|മാവു}} * {{Z|ms}}: {{W+|ms|tepung}} * {{Z|mt}}: {{W-|mt|dqiq|n}} * {{Z|mnc}}: {{W-|mnc|ᡠᡶᠠ}} * {{Z|mi}}: {{W+|mi|parāoa}} * {{Z|mrw}}: {{W-|mrw|tapong}}, {{W-|mrw|arina}} * {{Z|mr}}: {{W-|mr|पीठ|nt}} * {{Z|mhr}}: {{W-|mhr|ложаш}} * {{Z|hu}}: {{W+|hu|liszt}} * {{Z|ruq}}: {{W-|ruq|fărínă|m}} * {{Z|xmf}}: {{W-|xmf|ქვირი}} * {{Z|egy}}: {{W-egy|nḏ|h=nD-H_SPACE:nw-U9:Z2ss}} * {{Z|mwl}}: {{W-|mwl|farina|m}} * {{Z|moh}}: {{W-|moh|othèːseraʼ}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|гурил}} *: Mongolî: {{W-|mn|ᠭᠤᠯᠢᠷ}} * {{Z|nah}}: {{W+|nah|textli}} * {{Z|gld}}: {{W-|gld|опа}} * {{Z|nv}}: {{W-|nv|akʼáán}} * {{Z|nds}}: {{W-|nds|Meel|nt}} * {{Z|ne}}: {{W-|ne|पिठो}}, {{W-|ne|आटो}} * {{Z|nrf}}: {{W-|nrf|flieu|m}}, {{W-|nrf|flleur|m}} * {{Z|no}}: {{W-|no|mjøl|nt}} *: {{Z|no}}: {{W+|no|mel|nt}} * {{Z|oc}}: {{W+|oc|farina|m}} * {{Z|or}}: {{W-|or|ଅଟା}} * {{Z|ug}}: {{W-|ug|ئۇن}} * {{Z|uz}}: {{W+|uz|un}} * {{Z|ps}}: {{W+|ps|اوړه|n|tr=orha}} * {{Z|pms}}: {{W-|pms|farin-a|m}} * {{Z|pdt}}: {{W-|pdt|Mäl|nt}} * {{Z|pl}}: {{W+|pl|mąka|m}} * {{Z|pt}}: {{W+|pt|farinha|m}} * Puncabî: *: Şaxmuxî: {{W+|pa|آٹا|tr=āṭṭā}} *: Gurmuxî: {{W-|pa|ਆੱਟਾ|n}} * {{Z|kk}}: {{W-|kk|ұн}} * {{Z|mwr}}: {{W-|mwr|आटौ|n|tr=āṭau}} * {{Z|rhg}}: {{W-|rhg|fáki}} * {{Z|rgn}}: {{W-|rgn|faròina|m}} * {{Z|rm}}: {{W-|rm|farina|m}} * {{Z|rom}}: {{W-|rom|arro|n}} * {{Z|ro}}: {{W+|ro|făină|m}} * {{Z|ru}}: {{W+|ru|мука́}} * {{Z|sms}}: {{W-|sms|jävv}} * {{Z|sat}}: {{W-|sat|ᱯᱤᱴᱷᱟ}} * {{Z|sc}}: {{W-|sc|farína|m}} * {{Z|ceb}}: {{W-|ceb|harina}} * {{Z|scn}}: {{W+|scn|farina|m}} * {{Z|sd}}: {{W-|sd|اٽو|n|tr=aṭo|cuda=اَٽو}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|бра̏шно|nt}} *: Latînî: {{W+|sh|brȁšno|nt}} * {{Z|syc}}: {{W-|syc|ܩܡܚܐ|n|tr=qamḥɑ}} * {{Z|cu}}: *: Kirîlî: {{W-|cu|мѫка|m}}, {{W-|cu|брашьно|nt}} *: Glagolîtîk: {{W-|cu|ⰿⱘⰽⰰ|m}}, {{W-|cu|ⰱⱃⰰⱎⱐⱀⱁ|nt}} * {{Z|sk}}: {{W+|sk|múka|m}} * {{Z|sl}}: {{W+|sl|moka|m}} * {{Z|so}}: {{W+|so|daqiiq|n}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|muka|m}} *: {{Z|hsb}}: {{W-|hsb|muka|m}}, {{W-|hsb|mučka|m}} * {{Z|es}}: {{W+|es|harina|m}} * {{Z|sva}}: {{W-|sva|ფექ}}, {{W-|sva|ფაქუ̂}} * {{Z|sv}}: {{W+|sv|mjöl|nt}} * {{Z|xsr}}: {{W-|xsr|ཕེ}} * {{Z|tg}}: {{W-|tg|орд}} * {{Z|tl}}: {{W-|tl|harina}}, {{W+|tl|arina}} * {{Z|ta}}: {{W+|ta|மாவு}} * {{Z|rif}}: {{W-|rif|arn}} * {{Z|th}}: {{W+|th|แป้ง}} * {{Z|te}}: {{W+|te|పిండి}} * {{Z|tt}}: {{W+|tt|он}} * {{Z|tr}}: {{W+|tr|un}} * {{Z|tk}}: {{W-|tk|un}}, {{W-|tk|uun}} * {{Z|bo}}: {{W-|bo|ཕྱེ}} * {{Z|tpw}}: {{W-|tpw|uí}} * {{Z|udm}}: {{W-|udm|пызь}} * {{Z|uga}}: {{W-|uga|𐎖𐎎𐎈}} * {{Z|ur}}: {{W+|ur|آٹا|n|tr=āṭā}} * {{Z|uk}}: {{W+|uk|бо́рошно|nt}}, {{W-|uk|мука́|m}} * {{Z|vec}}: {{W+|vec|fior|n}} * {{Z|vep}}: {{W-|vep|jauh}} * {{Z|vi}}: {{W+|vi|bột}}, {{W+|vi|phấn}} * {{Z|vo}}: {{W-|vo|lemeil}} * {{Z|vro}}: {{W-|vro|jauh}}, {{W-|vro|jahu}} * {{Z|vot}}: {{W-|vot|javo}} * {{Z|wa}}: {{W+|wa|farene|m}}, {{W+|wa|fleur|m}} * {{Z|cy}}: {{W+|cy|blawd|n}}, {{W+|cy|can|n}} * {{Z|wym}}: {{W-|wym|māł|nt}}, {{W-|wym|maoł|nt}} * {{Z|km}}: {{W+|km|ម្សៅ|tr=msav}}, {{W-|km|ម្សៅមី|tr=msav mii}} * {{Z|yai}}: {{W-|yai|орта}} * {{Z|yi}}: {{W-|yi|מעל|m}} * {{Z|el}}: {{W+|el|αλεύρι|nt}} *: Kevn: {{W-|grc|ἄλευρον|nt}} *: {{Z|gmy}}: {{W-|gmy|𐀕𐀩𐀄𐀫}} *: {{Z|gmy}}: {{W-|gmy|𐀎}} {{werger-bin}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza|z=n}} # [[anî]], [[hanî]]<ref>[http://www.kovarabir.com/wp-content/uploads/Ferheng%C3%AA-Dimil%C3%AE-Zazak%C3%AE-%C3%BB-Kurmanc%C3%AE-A-a.pdf ''kovarabir.com'']</ref> #* {{bêmînak|zza}} === Çavkanî === {{çavkanî}} == {{ziman|ga}} == === Rengdêr === {{rengdêr|ga}} # [[bilind#ku|bilind]] #* {{bêmînak|ga}} cgwo1i8lwgxuzj5myjzhyut9kayf185 sabûn 0 20680 6291772 6262964 2026-07-28T01:40:24Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291772 wikitext text/x-wiki {{bnr-h|sabun|şabûn|şa bûn}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA|sˁabûn}}, {{ku-Arab|صابوون}} === Navdêr === [[Wêne:2010_Anudze,_Cevennes,_France_(2).jpg|thumb|çend [[qalib]]ên '''sabûnê'''.]] {{navdêr|ku|z=m}} # [[madde|Maddeyek]] [[kef]]dar e [[têkil]]î nav [[av]]ê têt kirin û tişt pê tên [[şûştin]] (bi [[gelemper]]î [[dirûv]]ê wê [[qalib]]ek [[req]] e lê bi avê têt [[helandin]]). #* {{bêmînak|ku}} ==== Bi alfabeyên din ==== * {{ku-ar|سابوون}} ==== Formên alternatîv ==== {{kol3|ku|cure=Herwiha | {{hw|ku|sabîn}} | {{hw|ku|sabwîn}} | {{hw|ku|sawîn}} | {{hw|ku|sawun}} | {{hw|ku|sawûn}} }} ==== Bide ber ==== {{kol3|ku |şampo |tayêt }} ==== Jê ==== {{kol3|ku|cure=Jê |sabûn kirin<pos:lêker> |sabûnkirin<pos:navdêr> |bêsabûn |bêsabûnî |bêsabûnîtî |bêsabûntî |bisabûn |sabûn dan |sabûndan |sabûndar |sabûndarî |sabûndarîtî |sabûndartî |sabûndayî |sabûnder |sabûnderî |sabûnfiroş |sabûnfiroşgeh |sabûnfiroşî |sabûnî |sabûnker |sabûn kirin |sabûnkirin |sabûnkirî |sabûnsaz |sabûnsazî |sabûnvan |sabûnvanî |sabûnvanîtî |sabûnvantî }} ==== Etîmolojî ==== Bi riya {{deyn|ar|ku|صَابُون}} ji {{ji|la|ku|sapo}} ji zimanekî [[keltî]] yan ji zimanekî [[cermenî]] ji {{ji|ine-pro|ku|*seib-}}, {{g|ine-pro|*sib-|tr=[[riştin]], [[rijandin]]}}. Heman peyv serekaniya hevmaneyên sabûnê yên bi zimanên din e jî (binere beşa wergerran li jêr). ==== Werger ==== {{werger-ser}} * {{Z|ab}}: {{W-|ab|асапын}} * {{Z|ace}}: {{W-|ace|sabôn}} * {{Z|ady}}: {{W-|ady|сабын}} * {{Z|af}}: {{W+|af|seep}} * {{Z|akl}}: {{W-|akl|habon}} * {{Z|sq}}: {{W+|sq|sapun|n}} * {{Z|goh}}: {{W-|goh|seipfa|m}}, {{W-|goh|seiffa|m}}, {{W-|goh|seifa|m}} * {{Z|de}}: {{W+|de|Seife|m}} * {{Z|alt}}: {{W-|alt|самын}} * {{Z|am}}: {{W-|am|ሳሙና}} * {{Z|arc}}: *: {{Z|syc}}: {{W-|syc|ܨܦܘܢܐ|n|tr=ṣappōnā}} * {{Z|rup}}: {{W-|rup|sãpuni|m}}, {{W-|rup|sãpune|m}} * {{Z|as}}: {{W-|as|চাবোন}} * {{Z|ast}}: {{W+|ast|xabón|n}} * {{Z|av}}: {{W-|av|сапун}} * {{Z|az}}: {{W+|az|sabun}} * {{Z|eu}}: {{W-|eu|xaboi}} * {{Z|ba}}: {{W-|ba|һабын}} * {{Z|be}}: {{W-|be|мы́ла|nt}} * {{Z|bn}}: {{W+|bn|সাবান}} * {{Z|br}}: {{W-|br|saon}}, {{W-|br|soavon}} * {{Z|mbb}}: {{W-|mbb|savun}} * {{Z|bg}}: {{W+|bg|сапу́н|n}} * {{Z|my}}: {{W+|my|ဆပ်ပြာ}} * {{Z|bua}}: {{W-|bua|мылэ}}, {{W-|bua|сабан}} * {{Z|ccc}}: {{W-|ccc|shawona}} * {{Z|ce}}: {{W-|ce|саба}} * {{Z|cs}}: {{W+|cs|mýdlo|nt}} * {{Z|chr}}: {{W-|chr|ᎣᎳ}}, {{W-|chr|ᎣᏝ}} * {{Z|ny}}: {{W-|ny|sopo}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|番鹼}}, {{W-|yue|番梘|tr=faan1 gaan2}} *: {{Z|dng}}: {{W-|dng|йизы}} *: {{Z|gan}}: {{W-|gan|肥皂|tr='fi4 cau5}} *: {{Z|hak}}: {{W-|hak|茶箍|tr=chhà-kû}}, {{W-|hak|番鹼|tr=fân-kién, fân-kián}}, {{W-|hak|石鹼|tr=sa̍k-kién}}, {{W-|hak|番鹼}} *: {{Z|cjy}}: {{W-|cjy|肥皂|tr=fei1 zau3}} *: {{Z|cmn}}: {{W+|cmn|肥皂|tr=féizào}} *: {{Z|mnp}}: {{W-|mnp|胰仔|tr=ǐ-ciě}} *: {{Z|cdo}}: {{W-|cdo|胰皂|tr=ì-cô̤}} *: {{Z|nan}}: {{W-|nan|雪文|tr=sat-bûn, sap-bûn, sap-mûi}}, {{W+|nan|茶箍|tr=tê-kho͘}}, {{W-|nan|油胰|tr=iû-i}} *:: Teochew: {{W-|nan|餅藥}}, {{W-|nan|饼药|tr=pian2 ioh8, pian2 iêh8}} *: {{Z|wuu}}: {{W-|wuu|肥皂}} *: {{Z|hsn}}: {{W-|hsn|肥皂|tr=fei2 zau5}} * {{Z|ckt}}: {{W-|ckt|муԓемуԓ|tr=muḷemuḷ}} * {{Z|cv}}: {{W-|cv|супӑнь}} * {{Z|dlm}}: {{W-|dlm|sapaun|n}} * {{Z|da}}: {{W+|da|sæbe|g}} * {{Z|dar}}: {{W-|dar|сапун}} * {{Z|dv}}: {{W-|dv|ސައިބޯނި}} * {{Z|ovd}}: {{W-|ovd|twål|n}} * {{Z|id}}: {{W+|id|sabun}} * {{Z|ar}}: {{W-|ar|صَابُون|n}} *: {{Z|arz}}: {{W-|arz|صابونة|m|tr=ṣabūna}}, {{W-|arz|صابون|n-p|tr=ṣabūn}} * {{Z|hy}}: {{W+|hy|օճառ}}, {{W+|hy|սապոն}} * {{Z|myv}}: {{W-|myv|сапонь}} * {{Z|eo}}: {{W+|eo|sapo}} * {{Z|et}}: {{W+|et|seep}} * {{Z|fa}}: {{W+|fa|صابون|tr=sâbun}} * {{Z|fo}}: {{W-|fo|sápa|m}} * {{Z|fi}}: {{W+|fi|saippua}} * {{Z|fr}}: {{W+|fr|savon|n}} * {{Z|fur}}: {{W-|fur|savon|n}} * {{Z|stq}}: {{W-|stq|Seepe|m}} * {{Z|gd}}: {{W-|gd|siabann|n}} * {{Z|gag}}: {{W-|gag|sabun}} * {{Z|gl}}: {{W+|gl|xabón|n}}, {{W+|gl|xabrón|n}} * {{Z|gu}}: {{W-|gu|સાબુ}} * {{Z|ka}}: {{W+|ka|საპონი}} * {{Z|haw}}: {{W-|haw|kopa}} * {{Z|ha}}: {{W-|ha|sabulu}} * {{Z|hi}}: {{W+|hi|साबुन|n}} * {{Z|nl}}: {{W+|nl|zeep|m}} * {{Z|hrx}}: {{W-|hrx|Seif|m}} * {{Z|he}}: {{W+|he|סַבּוֹן|n|tr=sabón|cuda=סבון \ סַבּוֹן}} * {{Z|io}}: {{W+|io|sapono}} * {{Z|ang}}: {{W-|ang|sāpe|m}} * {{Z|enm}}: {{W-|enm|sope}} * {{Z|en}}: {{W+|en|soap}} * {{Z|inh}}: {{W-|inh|сапа}} * {{Z|ia}}: {{W-|ia|sapon}} * {{Z|iu}}: {{W-|iu|ᐃᕐᒥᐅᑦ}} * {{Z|ga}}: {{W-|ga|gallúnach|m}}, {{W-|ga|sópa|n}} *: {{Z|sga}}: {{W-|sga|gallúinech}} * {{Z|it}}: {{W+|it|sapone|n}} * {{Z|is}}: {{W+|is|sápa|m}} * {{Z|ja}}: {{W+|ja|石鹸|tr=せっけん, sekken}}, {{W+|ja|シャボン|tr=shabon}} * {{Z|jra}}: {{W-|jra|ia čơƀu}} * {{Z|kbd}}: {{W-|kbd|сабын}} * {{Z|kl}}: {{W-|kl|qaqorsaat}} * {{Z|xal}}: {{W-|xal|савң}} * {{Z|kn}}: {{W+|kn|ಸಾಬೂನು}} * {{Z|krc}}: {{W-|krc|сапын|tr=sapın}} * {{Z|kaa}}: {{W-|kaa|sabın}} * {{Z|csb}}: {{W-|csb|mëdło|nt}} * {{Z|ca}}: {{W+|ca|sabó|n}} * {{Z|ky}}: {{W+|ky|самын}} * {{Z|si}}: {{W-|si|සබන්}} * {{Z|koi}}: {{W-|koi|майтöг}} * {{Z|ko}}: {{W+|ko|비누}}, {{W-|ko|석감}} * {{Z|crs}}: {{W-|crs|savon}} * {{Z|kum}}: {{W-|kum|сапун|tr=sapun}} * {{Z|lad}}: {{W-|lad|shavón|n}}, {{W-|lad|שאבון|n}} * {{Z|la}}: {{W-|la|sāpō|n}} * {{Z|lv}}: {{W-|lv|ziepes|m-p}} * {{Z|lo}}: {{W+|lo|ສະບູ່}} * {{Z|lez}}: {{W-|lez|запун}} * {{Z|lt}}: {{W+|lt|muilas|n}} * {{Z|lmo}}: {{W-|lmo|savon}}, {{W-|lmo|savun}} * {{Z|lb}}: {{W+|lb|Seef|m}} * {{Z|lnd}}: {{W-|lnd|sabun}} * {{Z|mdh}}: {{W-|mdh|sabun}} * {{Z|mk}}: {{W-|mk|сапун|n}} * {{Z|mg}}: {{W+|mg|savony}} * {{Z|ml}}: {{W+|ml|സോപ്പ്}} * {{Z|ms}}: {{W+|ms|sabun}} * {{Z|mt}}: {{W+|mt|sapuna|m}} * {{Z|gv}}: {{W-|gv|sheeabin|n}} * {{Z|mi}}: {{W-|mi|hopi}} * {{Z|mrw}}: {{W-|mrw|sabon}} * {{Z|mr}}: {{W-|mr|साबण}} * {{Z|hu}}: {{W+|hu|szappan}} * {{Z|mn}}: *: Kirîlî: {{W+|mn|саван}} *: Mongolî: {{W-|mn|ᠰᠠᠪᠤᠩ}} * {{Z|nah}}: {{W-|nah|āmōlli}} * {{Z|gld}}: {{W-|gld|мэлэ}} * {{Z|nv}}: {{W-|nv|táláwosh}} * {{Z|nds}}: *: {{Z|nds-de}}: {{W-|nds-de|Seep|m}} * {{Z|ne}}: {{W-|ne|सावुन}} * {{Z|nog}}: {{W-|nog|сабын}} * {{Z|nrf}}: {{W-|nrf|savon|n}} * {{Z|no}}: *: {{Z|nb}}: {{W+|nb|såpe|n|m}} *: {{Z|nn}}: {{W-|nn|såpe|m}} * {{Z|css}}: {{W-|css|hawun}} * {{Z|oc}}: {{W+|oc|sabon|n}} * {{Z|or}}: {{W-|or|ସାବୁନ}} * {{Z|om}}: {{W-|om|saamunaa}} * {{Z|osa}}: {{W-|osa|wépukxa}} * {{Z|os}}: {{W-|os|сапон}} * {{Z|ota}}: {{W-|ota|صابون|tr=sabun}} * {{Z|ug}}: {{W-|ug|سوپۇن}} * {{Z|uz}}: {{W+|uz|sovun}} * {{Z|pap}}: {{W-|pap|habon}} * {{Z|ps}}: {{W+|ps|سابون|n|tr=sābūn}} * {{Z|pms}}: {{W-|pms|savon|n}} * {{Z|pdt}}: {{W-|pdt|Seep|m}} * {{Z|pl}}: {{W+|pl|mydło|nt}} * {{Z|pt}}: {{W+|pt|sabão|n}}, {{W+|pt|sabonete|n}} * {{Z|pa}}: {{W+|pa|ਸਾਬਣ}} * {{Z|kk}}: {{W-|kk|сабын}} * {{Z|rki}}: {{W-|rki|သပုန်|tr=sa.pum}} * {{Z|rhg}}: {{W-|rhg|sabon}} * {{Z|rgn}}: {{W-|rgn|savôn|n}} * {{Z|rm}}: {{W-|rm|savun}}, {{W-|rm|savung}}, {{W-|rm|savùn}} * {{Z|ro}}: {{W+|ro|săpun|nt}} * {{Z|ru}}: {{W+|ru|мы́ло|nt}} * {{Z|se}}: {{W-|se|sáibbo}}, {{W-|se|sáibu}} * {{Z|sa}}: {{W+|sa|फेनक|nt}} * {{Z|sc}}: {{W-|sc|sabone}}, {{W-|sc|saboni}}, {{W-|sc|saoni}}, {{W-|sc|sapone}} * {{Z|scn}}: {{W+|scn|sapuni|n}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|са̀пӯн|n}} *: Latînî: {{W+|sh|sàpūn|n}} * {{Z|sk}}: {{W+|sk|mydlo|nt}} * {{Z|sl}}: {{W+|sl|milo|nt}} * {{Z|so}}: {{W-|so|saabuun}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|mydło|nt}} *: {{Z|hsb}}: {{W-|hsb|mydło|nt}} * {{Z|st}}: {{W-|st|sesepa}} * {{Z|es}}: {{W+|es|jabón|n}}, {{W-|es|sopín|n}} * {{Z|sw}}: {{W+|sw|sabuni}} * {{Z|sv}}: {{W+|sv|tvål|g}}, {{W+|sv|såpa|g}} * {{Z|shn}}: {{W-|shn|သပ်ႉပျႃႇ}} * {{Z|cjs}}: {{W-|cjs|сабын|tr=sabın}} * {{Z|tab}}: {{W-|tab|сябун}} * {{Z|tg}}: {{W+|tg|собун}} * {{Z|tl}}: {{W-|tl|sabon}} * {{Z|ta}}: {{W+|ta|சோப்பு}} * {{Z|blt}}: {{W-|blt|ꪎꪱꪡ꫁ꪮꪉ}} * {{Z|th}}: {{W+|th|สบู่}} * {{Z|te}}: {{W+|te|సబ్బు}} * {{Z|crh}}: {{W-|crh|sabun}} * {{Z|tt}}: {{W+|tt|сабын}} * {{Z|tet}}: {{W-|tet|sabaun}} * {{Z|ti}}: {{W-|ti|ሳሙና}} * {{Z|tr}}: {{W+|tr|sabun}} * {{Z|tk}}: {{W-|tk|sabyn}} * {{Z|to}}: {{W-|to|koa}} * {{Z|tum}}: {{W-|tum|sopo}} * {{Z|tyv}}: {{W-|tyv|саваң}} * {{Z|udm}}: {{W-|udm|майтал}} * {{Z|ur}}: {{W-|ur|صابن|n|tr=sābun}} * {{Z|uk}}: {{W-|uk|ми́ло|nt}} * {{Z|vec}}: {{W+|vec|saon|n}}, {{W-|vec|savon}} * {{Z|vi}}: {{W+|vi|xà phòng}}, {{W+|vi|xà bông}} * {{Z|vo}}: {{W+|vo|sob}} * {{Z|cy}}: {{W+|cy|sebon|n}} * {{Z|wym}}: {{W-|wym|zaof|m}} * {{Z|wo}}: {{W+|wo|saabu}} * {{Z|kjh}}: {{W-|kjh|сабын}} * {{Z|km}}: {{W+|km|សាប៊ូ}} * {{Z|sah}}: {{W-|sah|мыыла}} * {{Z|tao}}: {{W-|tao|siken}} * {{Z|yi}}: {{W-|yi|זייף|m|nt}} * {{Z|yo}}: {{W-|yo|ọṣẹ}} * {{Z|el}}: {{W+|el|σαπούνι|nt}} *: Kevn: {{W-|grc|σμῆμα|nt}}, {{W-|grc|σμῆγμα|nt}}, {{W-|grc|ῥύμμα|nt}}, {{W-|grc|σάπων|n}} * {{Z|za}}: {{W-|za|yangzgenj}}, {{W-|za|genj}} {{werger-bin}} :{{werger çavkanî|en|soap|beş=Ev qismê Wergerê|oldid=75682269}} 3l8gdl75oxd8rdararx3ff1agxjjg82 tesewif 0 22348 6291718 6263690 2026-07-27T21:41:52Z Wikihez 7344 6291718 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|tesewif|mê}} {{navdêr|ku|z=m}} # [[sofîgerî|Sofîgerî]]: [[bawerî|Baweriya]] yan [[jiyan]]a [[sofî|sofiyan]]. #: {{hevmaneyên peyvê|ku|sofîtî|oldarî|dîndarî|teqwatî}} ==== Formên alternatîv ==== * {{g|ku|tesewuf}} ==== Têkildar ==== * {{g|ku|sofî}} ==== Jê ==== {{col3|ku|tesewifî|mutesewif}} ==== Etîmolojî ==== Ji {{deyn|ar|ku|تَصَوُّف}}. ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|soefisme}} * {{Z|de}}: {{W-|de|sufismus}}, {{W+|de|Sufismus|m}} * {{Z|da}}: {{W-|da|sufisme}} * {{Z|ar}}: {{W-|ar|تَصَوُّف}} * {{Z|eo}}: {{W-|eo|sufiismo}} * {{Z|fi}}: {{W+|fi|suufilaisuus}} * {{Z|fr}}: {{W+|fr|soufisme}} * {{Z|nl}}: {{W+|nl|soefisme}} * {{Z|he}}: {{W-|he|סופיות}} * {{Z|en}}: {{W+|en|sufism}} * {{Z|it}}: {{W-|it|sufismo}} * {{Z|ja}}: {{W-|ja|スーフィズム}} * {{Z|sh}}: {{W-|sh|ufizam}}, {{W-|sh|tasavuf}} * {{Z|es}}: {{W-|es|sufismo}} * {{Z|tr}}: {{W+|tr|tasavvuf}} {{werger-bin}} 74u5omrcaam16z0hk9h4bmb5rdph77z kîte 0 22629 6291633 6212203 2026-07-27T12:22:11Z Mehmet Can Demir 11086 /* Navdêr */ Nivîsa xelet sererast kirin 6291633 wikitext text/x-wiki {{standardkirin|kîte|kite}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|kîte|mê|guherto=hemû}} {{navdêr|ku|z=m}} # {{guharto|ku|kite}} ==== Jê ==== * {{mj|lêker}} [[kîte kirin]] wez-re-ba * {{mj|navdêr}} [[kîtekirin]] wez-re-ba ==== Werger ==== {{werger-bnr|hece}} 90g3aodo45dbz65ucjdte0r8q0q7d0u 6291635 6291633 2026-07-27T12:27:51Z Wikihez 7344 Reverted 1 edit by [[Special:Contributions/Mehmet Can Demir|Mehmet Can Demir]] ([[User talk:Mehmet Can Demir|talk]]): Ji kerema xwe sayfeya [[wezreba]] çêke û li kû derê tê bikaranîn binivîse ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291635 wikitext text/x-wiki {{standardkirin|kîte|kite}} == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|kîte|mê|guherto=hemû}} {{navdêr|ku|z=m}} # {{guharto|ku|kite}} ==== Jê ==== * {{mj|lêker}} [[kîte kirin]] * {{mj|navdêr}} [[kîtekirin]] ==== Werger ==== {{werger-bnr|hece}} hvn9i981hqok0a65vjkhnvgq1ywwrjx Ke'be 0 30704 6291755 6255914 2026-07-27T23:19:49Z Wikihez 7344 /* Serenav */ 6291755 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Serenav === [[Wêne:Mosquée Masjid el Haram à la Mecque.jpg|thumb|Ke'be.]] {{wp|Kabe}} {{serenav|ku|z=m}} # {{e|ku|Îslam}} [[kevir|Kevirê]] [[reş]] yê [[hec]]ê yê ku [[hecac]] li dor [[zivirîn|dizivirin]] û yê ku [[misilman]] [[berê xwe dan|berê xwe didin]]ê dema ku [[nivêj]]ê dikin. #* {{jêder|ku|{{Jêgirtin/Melayê Cizîrî/Dîwana Melayê Cizirî}}|jêgirtin=Leşkerê qehr û xeman wê çûn hisara dil bikin</br>'''Ke'be''' û Beytu l-heram e lê bi nûr bêtin receb</br>Suftiyên pir le'l û mircanan bi mujganan heta}} # Her cihê [[pîroz]]. #* {{bêmînak|ku}} ==== Formên alternatîv ==== * {{g|ku|Kabe}} * {{g|ku|Ka'be}} * {{g|ku|Kebe}} ==== Jê ==== * {{g|ku|ke'beyî}} ==== Etîmolojî ==== Deyn ji {{deyn|ar|ku|الْكَعْبَة}}. ==== Werger ==== {{werger-ser}} * {{Z|sq}}: {{W-|sq|Qabeja}} * {{Z|de}}: {{W+|de|Kaaba}} * {{Z|az}}: {{W-|az|Kəbə}} * {{Z|ba}}: {{W-|ba|Ҡәғбә}} * {{Z|bn}}: {{W-|bn|কাবা}}, {{W-|bn|খানে কাবা}}, {{W-|bn|কাবাঘর}} * {{Z|bg}}: {{W-|bg|Кааба}} * {{Z|zh}}: *: {{Z|cmn}}: {{W+|cmn|克爾白|tr=Kè'ěrbái}}, {{W+|cmn|天房|tr=Tiānfáng}} * {{Z|da}}: {{W-|da|Ka'ba}} * {{Z|dar}}: {{W-|dar|КагӀба}} * {{Z|id}}: {{W-|id|Ka'bah}} * {{Z|ar}}: {{W+|ar|الْكَعْبَة|m}}, {{W-|ar|الْكَعْبَة الْمُشَرَّفَة|m|tr=al-kaʕba l-mušarrafa}} * {{Z|eo}}: {{W-|eo|Kaabo}} * {{Z|et}}: {{W+|et|Kaaba}} * {{Z|fa}}: {{W+|fa|کعبه|tr=ka'be}} * {{Z|fi}}: {{W-|fi|Kaaba}} * {{Z|fr}}: {{W-|fr|Ka'ba}} * {{Z|hi}}: {{W+|hi|काबा}} * {{Z|nl}}: {{W-|nl|Ka'aba}} * {{Z|he}}: {{W-|he|כַּעְבָּה|tr=ka'ba|m}} * {{Z|en}}: {{W+|en|Kaaba }} * {{Z|it}}: {{W-|it|Ka'ba|m}} * {{Z|is}}: {{W-|is|Kaba}} * {{Z|ja}}: {{W-|ja|カアバ|tr=kāba}} * {{Z|lt}}: {{W-|lt|Kaaba|m}} * {{Z|mk}}: {{W-|mk|Ќаба|m}}, {{W-|mk|Каба|m}} * {{Z|ms}}: {{W-|ms|Kaabah}} * {{Z|mr}}: {{W-|mr|काबा}} * {{Z|hu}}: {{W+|hu|Kába}} * {{Z|no}}: {{W-|no|Kaba}} * {{Z|ug}}: {{W-|ug|كەئبە}} * {{Z|uz}}: {{W-|uz|Kaʼba}} * {{Z|pl}}: {{W+|pl|Kaaba|m}} * {{Z|pt}}: {{W+|pt|Kaaba|m}} * {{Z|rhg}}: {{W-|rhg|Kaabá}} * {{Z|ru}}: {{W+|ru|Ка́аба|m}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|Ка́ба|m}}, {{W-|sh|Ћа́ба|m}} *: Latînî: {{W-|sh|Kába|m}}, {{W-|sh|Ćába|m}} * {{Z|sk}}: {{W-|sk|Kába|m}} * {{Z|es}}: {{W-|es|Kaaba|m}} * {{Z|sw}}: {{W+|sw|Kaaba}} * {{Z|sv}}: {{W-|sv|Kaba}} * {{Z|tg}}: {{W-|tg|Каъба}} * {{Z|ta}}: {{W+|ta|காபா}} * {{Z|th}}: {{W-|th|กะอฺบะหฺ|tr=gà’bàh}} * {{Z|crh}}: {{W-|crh|Kâbe}} * {{Z|tr}}: {{W+|tr|Kâbe}} * {{Z|ur}}: {{W-|ur|کعبہ|tr=ka'ba}} {{werger-bin}} :{{werger çavkanî|en|Kaaba|beş=Ev qismê Wergerê|oldid=76703205}} 4wgac6vgoc8onalx5jlqwhljybwq02m derdan 0 30896 6291824 6279972 2026-07-28T08:01:56Z ~2026-39551-86 15142 /* Lêker */ 6291824 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/dɛɾˈdɑːn/}} * {{kîte|ku|der|dan}} === Lêker === {{lêker|ku|c=?}} # Di [[leyîz|Leyîz]] an [[yarî|yari]]yê de xusar bûn an di leyîzê de têkçûn. #: ''min leyîz '''derda'''.'' # misînên avê, bîdonên avê ==== Bide ber ==== * [[derdank]] ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser}} * {{Z|fa}}: {{W|fa|باختن}} * {{Z|en}}: {{W|en|lose}}, {{W|en|shut out}} * {{Z|tr}}: {{W|tr|kaybetmek}} {{werger-bin}} === Navdêr === {{navdêr|ku|z=?}} # ''Binere'': '''''[[derdank]]''''' 9j16yzjeogbrmkqtzr10lgajso829k5 onur 0 52915 6291773 6261670 2026-07-28T01:41:20Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291773 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/oːˈnʊɾ/}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|onur|mê}} {{navdêr|ku|z=m}} # [[şanazî]], [[rûmet]], [[firazî]], [[fîz]], [[şeref]], [[heysiyet]], [[şan]], [[hesiyet]], [[weqar]] #* {{jêder|ku|jêgirtin=Bi sîstema federalî, kurd dê jiyaneke bi onur û bi şeref ava bikin. Dê nasnameya xwe bi serbilindî biparêzin û pêş bixin.|Îbrahîm Guçlu: ''Divê kurd [[kêmtirîn]] Kurdistaneka federe bixwazin'', Netkurd.com, 8/2009}} ==== Formên alternatîv ==== * {{g|ku|onûr}} ==== Têkildar ==== * {{g|ku|onore}} ==== Jê ==== {{kol3|ku|cure=Jê |bêonur |bêonurî |bêonurîtî |bêonurtî |bionur |bionurî |onurandin |onurandî |onurdar |onurdarî |onurî |onurîner }} ==== Etîmolojî ==== Deyn ji {{deyn|tr|ku|onur}} ji {{ji|fr|ku|honneur}}. ==== Werger ==== {{werger-ser}} * {{Z|fi}}: {{W+|fi|kunnia}}, {{W+|fi|maine}} * {{Z|fr}}: {{W+|fr|honneur}} * {{Z|en}}: {{W-|en|honor}} [[honour]] * {{Z|tr}}: {{W+|tr|onur}}, {{W+|tr|şeref}}, {{W+|tr|haysiyet}} {{werger-bin}} == {{ziman|tr}} == === Bilêvkirin === * {{deng|tr|LL-Q256 (tur)-ToprakM-onur.wav|Deng|dever=Îzmîr, Tirkiye}} === Navdêr === {{navdêr|tr}} # [[xawên]], [[rûmet]], [[şanazî]] #* {{bêmînak|tr}} # [[weqar]], [[hesiyet]] #* {{bêmînak|tr}} # [[şeref]] #* {{bêmînak|tr}} n4shfcl2g0gyf5s6s2gj8dpy4ey9obf Rebellion 0 55092 6291793 5920789 2026-07-28T02:26:49Z Wikihez 7344 /* Bilêvkirin */ 6291793 wikitext text/x-wiki {{bnr-h|rebellion}} == {{ziman|de}} == === Bilêvkirin === * {{deng|de|De-Rebellion.ogg|nivîs=Rebellion}} === Navdêr === {{navdêr|de|z=m}} # [[serhildan]] #* {{bêmînak|de}} qt641ssmu6137j4muoyhqhr5jpjuea7 werzeba 0 60142 6291630 6289132 2026-07-27T12:14:53Z Mehmet Can Demir 11086 Min nivîsa xelet sererast kir, navê peyva 'werzeba' wekî 'wezreba' sererast kir. 6291630 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin ===Wezreba ye,ne werzeba ye. Ji ber ko koka navê xwe ji 'wezîn'ê digire. Wezîn,tê wateya ba rabûnê,ba hatinê, yanê na diwezîn e, nawerzîn e. * {{ku-IPA}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|wezreba|mê}} {{navdêr|ku|z=m}} # {{f|ku|Qerejdax}}<ref>{{kovara kurmancî|hejmar=28|sernav=Devoka Qerejdaxê|nivîskar=Mehmûd Lewendî|r=2}}</ref> Bayê pir qalim, bayê diwezîne, bayê sar. # Bayê dawiya adarê û destpêka meha nîsanê ye. Bi vî bayî re bişkoj dara diteqin û kulîlk vedidin. #: {{jêder|ku|jêgirtin=Îsal '''wezreba''' dereng ma, daran gul veneda.|SZK Medya, bernamaye "Her carê peyvek" li ser youtube, xeleka 34.}} #: {{jêder|ku|jêgirtin=Vêga bişkojên dara me li benda '''wezrebayê''' ne.|SZK Medya, bernamaye "Her carê peyvek" li ser youtube, xeleka 34.}} ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser|1}} * {{Z|fr}}: {{W-|fr|vent du nord-est}} * {{Z|en}}: {{W+|en|monsoon|guman=erê}}, {{W-|en|seasonal wind|guman=erê}}, {{W-|en|north-east wind}} * {{Z|tr}}: {{W-|tr|kuzeydoğu rüzgârı}} {{werger-bin}} {{werger-ser|2}} {{werger-bin}} === Çavkanî === koka peyvê, {{çavkanî}} koka peyvê, wekî;'ba diwezîn e', "ba, hêdî hêdî dewezîn e, wezreba dest pê kiriye" 0xojd6tf3lb22vkf1sl304f1ecrur9r 6291632 6291630 2026-07-27T12:17:46Z Mehmet Can Demir 11086 /* Kurmancî */ Nivîsa xelet sererast kirin. 6291632 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin ===Wezreba ye,ne werzeba ye. Ji ber ko koka navê xwe ji 'wezîn'ê digire. Wezîn,tê wateya ba rabûnê,ba hatinê, yanê diwezîn e, nawerzîn e. * {{ku-IPA}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|wezreba|mê}} {{navdêr|ku|z=m}} # {{f|ku|Qerejdax}}<ref>{{kovara kurmancî|hejmar=28|sernav=Devoka Qerejdaxê|nivîskar=Mehmûd Lewendî|r=2}}</ref> Bayê pir qalim, bayê diwezîne, bayê sar. # Bayê dawiya adarê û destpêka meha nîsanê ye. Bi vî bayî re bişkoj dara diteqin û kulîlk vedidin. #: {{jêder|ku|jêgirtin=Îsal '''wezreba''' dereng ma, daran gul veneda.|SZK Medya, bernamaye "Her carê peyvek" li ser youtube, xeleka 34.}} #: {{jêder|ku|jêgirtin=Vêga bişkojên dara me li benda '''wezrebayê''' ne.|SZK Medya, bernamaye "Her carê peyvek" li ser youtube, xeleka 34.}} ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser|1}} * {{Z|fr}}: {{W-|fr|vent du nord-est}} * {{Z|en}}: {{W+|en|monsoon|guman=erê}}, {{W-|en|seasonal wind|guman=erê}}, {{W-|en|north-east wind}} * {{Z|tr}}: {{W-|tr|kuzeydoğu rüzgârı}} {{werger-bin}} {{werger-ser|2}} {{werger-bin}} === Çavkanî === koka peyvê, {{çavkanî}} koka peyvê, wekî;'ba diwezîn e', "ba, hêdî hêdî diwezîn e, wezreba dest pê kiriye" 41zt9m0q8w6qr8r1ogh3nlioft9k06l 6291639 6291632 2026-07-27T13:09:42Z Wikihez 7344 6291639 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|wezreba|mê}} {{navdêr|ku|z=m}} # {{f|ku|Qerejdax}}<ref>{{kovara kurmancî|hejmar=28|sernav=Devoka Qerejdaxê|nivîskar=Mehmûd Lewendî|r=2}}</ref> [[ba|Bayê]] pir [[qalim]], bayê [[wezîn|diwezîne]], bayê [[sar]]. # [[ba|Bayê]] [[dawî|dawiya]] [[adar|adarê]] û [[destpêk|destpêka]] [[meh|meha]] [[nîsan|nîsanê]] ye. Bi vî [[ba|bayî]] re [[bişkoj]] [[dar|dara]] [[teqîn|diteqin]] û [[kulîlk]] [[vedan|vedidin]]. #* {{jêder|ku|jêgirtin=Îsal '''wezreba''' dereng ma, daran gul veneda.|SZK Medya, bernamaye "Her carê peyvek" li ser Youtube, xeleka 34.}} #* {{jêder|ku|jêgirtin=Vêga bişkojên dara me li benda '''wezrebayê''' ne.|SZK Medya, bernamaye "Her carê peyvek" li ser Youtube, xeleka 34.}} ==== Formên alternatîv ==== * {{alt|ku|wezreba}} ==== Etîmolojî ==== Ji {{qf|ku|wezîn<t:ba rabûn, ba hatin>|ba}}. ==== Werger ==== {{werger-ser|1}} * {{Z|fr}}: {{W-|fr|vent du nord-est}} * {{Z|en}}: {{W+|en|monsoon|guman=erê}}, {{W-|en|seasonal wind|guman=erê}}, {{W-|en|north-east wind}} * {{Z|tr}}: {{W-|tr|kuzeydoğu rüzgârı}} {{werger-bin}} {{werger-ser|2}} {{werger-bin}} ==== Çavkanî ==== {{çavkanî}} kk7u2q2mk61qy4afwiqjef6z7dug3rq 6291694 6291639 2026-07-27T20:04:08Z Wikihez 7344 /* Formên alternatîv */ https://ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAja_bikarh%C3%AAner:Mehmet_Can_Demir&oldid=6291656#c-Mehmet_Can_Demir-20260727135500-Wikihez-20260727131000 6291694 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-IPA}} * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|wezreba|mê}} {{navdêr|ku|z=m}} # {{f|ku|Qerejdax}}<ref>{{kovara kurmancî|hejmar=28|sernav=Devoka Qerejdaxê|nivîskar=Mehmûd Lewendî|r=2}}</ref> [[ba|Bayê]] pir [[qalim]], bayê [[wezîn|diwezîne]], bayê [[sar]]. # [[ba|Bayê]] [[dawî|dawiya]] [[adar|adarê]] û [[destpêk|destpêka]] [[meh|meha]] [[nîsan|nîsanê]] ye. Bi vî [[ba|bayî]] re [[bişkoj]] [[dar|dara]] [[teqîn|diteqin]] û [[kulîlk]] [[vedan|vedidin]]. #* {{jêder|ku|jêgirtin=Îsal '''wezreba''' dereng ma, daran gul veneda.|SZK Medya, bernamaye "Her carê peyvek" li ser Youtube, xeleka 34.}} #* {{jêder|ku|jêgirtin=Vêga bişkojên dara me li benda '''wezrebayê''' ne.|SZK Medya, bernamaye "Her carê peyvek" li ser Youtube, xeleka 34.}} ==== Formên alternatîv ==== * {{alt|ku|wezreba||Hîzan|Bedlîs}} ==== Etîmolojî ==== Ji {{qf|ku|wezîn<t:ba rabûn, ba hatin>|ba}}. ==== Werger ==== {{werger-ser|1}} * {{Z|fr}}: {{W-|fr|vent du nord-est}} * {{Z|en}}: {{W+|en|monsoon|guman=erê}}, {{W-|en|seasonal wind|guman=erê}}, {{W-|en|north-east wind}} * {{Z|tr}}: {{W-|tr|kuzeydoğu rüzgârı}} {{werger-bin}} {{werger-ser|2}} {{werger-bin}} ==== Çavkanî ==== {{çavkanî}} e4pf2gla3mf1jrpuf24ipf2xu5faznp teşt 0 60654 6291687 6288516 2026-07-27T18:41:18Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291687 wikitext text/x-wiki {{bnr-h|Test|test|têst}} == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/tˤɛʃt/}} === Navdêr === {{ku-tewîn-nav|teşt|mê}} {{navdêr|ku|z=m}}, {{t-ya nerm}} (1,2) # [[test]], [[alav]]ek [[servekirî]] ye, ne [[kûr]] e, bi piranî [[girover]] e û ji plastîk hatiye çêkirin<br> Tê de çek ([[cil]]) têne [[şûştin]] yan jî mirov, bi taybetî zarok, tê de xwe dişon # [[zembîl]], [[selik]], [[sepet]], [[sevî]] #* {{jêder|ku|jêgirtin=Ferzend bi lez perçak nan ji '''teştê''' derxist, derket û bazda.|{{Jêgirtin/Firat Cewerî/Girtî}}}} ==== Bi alfabeyên din ==== * {{ku-ar|ته‌شت}} ==== Bide Ber ==== * [[legan]] * [[dist]] * [[mencel]] ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|bak}} * {{Z|de}}: {{W+|de|Becken|nt}}, {{W+|de|Waschbecken|nt}} * {{Z|alt}}: {{W-|alt|табак}} * {{Z|eu}}: {{W-|eu|arroa}} * {{Z|br}}: {{W+|br|basin|m}} * {{Z|bg}}: {{W+|bg|умива́лник|n}} * {{Z|cs}}: {{W-|cs|umyvadlo|nt}} * {{Z|ny}}: {{W-|ny|beseni}} * {{Z|zh}}: *: {{Z|cmn}}: {{W+|cmn|洗滌槽|tr=xǐdícáo}} * {{Z|da}}: {{W+|da|bassin|nt}} * {{Z|id}}: {{W+|id|wastafel}} * {{Z|ar}}: {{W-|ar|طَشْت|m}} *: {{Z|arz}}: {{W-|arz|حوض|n|tr=ḥōḍ}} * {{Z|hy}}: {{W+|hy|կոնք}} * {{Z|eo}}: {{W-|eo|pelvo}}, {{W+|eo|lavabo}}, {{W+|eo|baseno}}, {{W-|eo|lavujo}} * {{Z|fa}}: {{W+|fa|لگن|tr=lagan}}, {{W+|fa|تشت|tr=tašt}}, {{W+|fa|لانجین|tr=lânjin}} * {{Z|fi}}: {{W+|fi|pesuallas}} ; {{W-|fi|pesuvati}} ; {{W+|fi|allas}} * {{Z|fr}}: {{W+|fr|cuvette|m}}, {{W+|fr|bassine|m}}, {{W+|fr|lavabo|n}} * {{Z|gd}}: {{W-|gd|amar|n}} * {{Z|gl}}: {{W-|gl|bacía|m}}, {{W+|gl|pía|m}} * {{Z|ka}}: {{W-|ka|აუზი}} * {{Z|ht}}: {{W-|ht|basin}}, {{W-|ht|basen}} * {{Z|nl}}: {{W+|nl|bassin|nt}} * {{Z|he}}: {{W+|he|אַגָּן|n|tr=agán}} * {{Z|io}}: {{W+|io|baseno}} * {{Z|ang}}: {{W-|ang|ċēac|n}} * {{Z|enm}}: {{W-|enm|basyn}} * {{Z|en}}: {{W+|en|basin}} * {{Z|ga}}: {{W-|ga|báisín|n}} * {{Z|it}}: {{W+|it|lavandino|n}}, {{W+|it|lavabo|n}}, {{W+|it|bacinella|m}}, {{W+|it|lavacro|n}}, {{W+|it|lavello|n}} * {{Z|ja}}: {{W+|ja|盥|tr=たらい, tarai}} * {{Z|ca}}: {{W+|ca|pica|m}} * {{Z|ky}}: {{W+|ky|миска}}, {{W+|ky|табак}}, {{W+|ky|миска}}, {{W+|ky|тепши}}, {{W+|ky|бассейн}}, {{W+|ky|раковина}}, {{W+|ky|көлмө}}, {{W+|ky|резервуар}}, {{W+|ky|ванна}}, {{W+|ky|таз}}, {{W+|ky|дагара}}, {{W+|ky|илеген}}, {{W+|ky|чылапчын}}, {{W+|ky|кудукча}}, {{W+|ky|кудук}}, {{W+|ky|кювета}}, {{W+|ky|котловина}} * {{Z|ko}}: {{W+|ko|대야}} * {{Z|la}}: {{W-|la|alveus|n}}, {{W-|la|lābrum|nt}}, {{W-|la|pelvis|n}} * {{Z|lv}}: {{W+|lv|bļoda|m}} * {{Z|luy}}: {{W-|luy|ekarai}}, {{W-|luy|ebeseni}} * {{Z|mk}}: {{W-|mk|мијалник|n}}, {{W-|mk|лавабо́|nt}} * {{Z|ms}}: {{W-|ms|besen}} * {{Z|mi}}: {{W-|mi|peihana}} * {{Z|mer}}: {{W-|mer|karai}} * {{Z|nrf}}: {{W-|nrf|bachîn|n}} * {{Z|no}}: {{W-|no|servant|n}}, {{W-|no|vaskekum|n}}, {{W-|no|balje|n}} * {{Z|pl}}: {{W+|pl|umywalka|m}} * {{Z|pt}}: {{W+|pt|bacia|m}}, {{W+|pt|pia|m}} * {{Z|cop}}: {{W-|cop|ⲙⲉⲣⲁⲛ|n}} * {{Z|ro}}: {{W+|ro|chiuvetă|m}} * {{Z|ru}}: {{W+|ru|таз|n}}, {{W+|ru|умыва́льник|n}} * {{Z|rue}}: {{W-|rue|лавор|m}} * {{Z|es}}: {{W+|es|pileta|m}}, {{W+|es|lavabo|n}}, {{W+|es|lavamanos|n}}, {{W+|es|jofaina|m}}, {{W+|es|palangana|m}} * {{Z|sw}}: {{W+|sw|karai}}, {{W+|sw|beseni}} * {{Z|sv}}: {{W+|sv|tvättfat|nt}}, {{W+|sv|handfat|nt}} * {{Z|tl}}: {{W-|tl|palanggana|nt}}, {{W-|tl|lababo}} * {{Z|th}}: {{W-|th|อ่างล้างหน้า}}, {{W+|th|อ่าง}} * {{Z|tr}}: {{W+|tr|tekne}}, {{W+|tr|leğen}} * {{Z|tk}}: {{W-|tk|legen}} * {{Z|tpi}}: {{W-|tpi|dis}}, {{W-|tpi|plet}} * {{Z|uga}}: {{W-|uga|𐎒𐎔𐎍}} * {{Z|uk}}: {{W-|uk|таз|n}} * {{Z|vi}}: {{W-|vi|cái chảo}} * {{Z|km}}: {{W-|km|អាងលាងសំអាត}} * {{Z|yi}}: {{W-|yi|ביט|n}}, {{W-|yi|בעקן|n}} * {{Z|el}}: {{W+|el|νιπτήρας|n}} *: Kevn: {{W-|grc|νιπτήρ|n}} {{werger-bin}} :{{werger çavkanî|en|basin|beş=Ev qismê Wergerê|oldid=75873332}} 1wlyp0ovnl0o0o71o0wqqiiqozpefbm Wîkîferheng:Peyvekê çêke 4 118706 6291662 6026094 2026-07-27T15:53:39Z Wikihez 7344 6291662 wikitext text/x-wiki Ji bo çêkirina madeyeke nû li qutiya li jêr peyvê binivîsîn û pê li "{{int:Inputbox-createarticle}}" bikin. Formeke bo nivîsîna agahiyan dê were pêşberî we. Divê maneya her peyv bi kurdiya kurmancî were nivîsîn. Ji bo zêdetir alîkarî binêrin [[Alîkarî:Formata nivîsînê]]. == Forma bo çêkirina peyvekê == <div class="standard-box" style="display:inline-block; width:250px; margin-bottom:3px; padding-top:1px; border:1px solid black; text-align:center;"> '''Sernavê rûpelê binivîse''' {{#tag:inputbox | type=create width=22 bgcolor=var(--wikt-palette-lightergrey, #F4F4F4) editintro= default= break=yes }} </div> [[Kategorî:Wîkîferheng]] 53lrult6a5l30tbxl3heb6w3ptdrod8 dayak düşkünü 0 131126 6291813 5796888 2026-07-28T05:42:19Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +tr:navdêr:test {{îzah|kesê ku kutana (lêdan an jî lêxistina) xwe heq kiriye, xwe aniye lêxistinê}} 6291813 wikitext text/x-wiki == {{ziman|tr}} == === Navdêr === {{navdêr|tr}} #[[kesê]] ku [[kutan]]a ([[lêdan]] [[an jî]] [[lêxistin]]a) [[xwe]] [[heq kirin|heq kiriye]], xwe [[anîn|aniye]] [[lêxistin]]ê #: {{hevmane|tr|dayak kaçkını}} #* {{bênimûne|tr}} ne7cc3lanapoq75gc29xijmsnegipdw iki büklüm olmak 0 142811 6291660 4642301 2026-07-27T15:06:46Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291660 wikitext text/x-wiki == {{ziman|tr}} == === Lêker === {{lêker|tr}} # [[qulûzî bûn]], [[piştqulûzî bûn]], [[bi dev çûn erdê]], [[xûl bûn]], [[kolî () bûn]], di hev de tewîn (ji ber nexweşîn, pîr ûkaliyi) # bi dev çûn erdê, [[xûl bûn]], [[kolî () bûn]], (ji bo giramiyê) r2izr0ylex29pbxt6l52zewus1nx863 rebellion 0 201190 6291794 4549478 2026-07-28T02:28:15Z Wikihez 7344 /* Navdêr */ 6291794 wikitext text/x-wiki == {{ziman|en}} == === Navdêr === {{navdêr|en}} # [[îsyan]], [[raperîn]], [[nerazîbûn]], [[serhildan]], [[pîlangerî]], [[serdegirtin]] fbt09uqwlaq5bjxghrmqg0oeu8xwts6 bazdayî 0 208502 6291720 5886337 2026-07-27T21:54:22Z Wikihez 7344 6291720 wikitext text/x-wiki == {{ziman|ku}} == === Rengdêr === {{rengdêr|ku}} #{{mane?} ==== Etîmolojî ==== Ji {{q|ku|bazdan}}. ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|geflohen}}, {{W+|de|gegangen}}, {{W+|de|gelaufen}} * {{Z|en}}: {{W+|en|escapee}}, {{W+|en|pranced|guman=erê}} {{werger-bin}} b4qgdi6fgquijrx7iv2fh678fm2ju8j 6291721 6291720 2026-07-27T21:54:30Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291721 wikitext text/x-wiki == {{ziman|ku}} == === Rengdêr === {{rengdêr|ku}} #{{mane?}} ==== Etîmolojî ==== Ji {{q|ku|bazdan}}. ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|geflohen}}, {{W+|de|gegangen}}, {{W+|de|gelaufen}} * {{Z|en}}: {{W+|en|escapee}}, {{W+|en|pranced|guman=erê}} {{werger-bin}} lqlj7k95jijag7ai3f92zm7yv2dkkq8 6291780 6291721 2026-07-28T02:15:12Z Balyozbot 7867 Bot: Sererastkirina şablonan û koda zimên 6291780 wikitext text/x-wiki == {{ziman|ku}} == === Rengdêr === {{rengdêr|ku}} #{{mane?|ku}} ==== Etîmolojî ==== Ji {{q|ku|bazdan}}. ==== Werger ==== {{werger-ser}} * {{Z|de}}: {{W+|de|geflohen}}, {{W+|de|gegangen}}, {{W+|de|gelaufen}} * {{Z|en}}: {{W+|en|escapee}}, {{W+|en|pranced|guman=erê}} {{werger-bin}} d9jk9gpjfjis2jodz32hpmgm5hjxw43 hematolojî 0 296512 6291642 6291623 2026-07-27T13:13:23Z Ghybu 1393 /* Têkilîdar */ 6291642 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|hematolojî|mê}} {{navdêr|ku|z=m}} # [[xwînnasî]], [[vekolîn]]ên [[bijîşkî]] li ser [[xwîn]]a [[nexweş]]an #* {{jêder|ku|jêgirtin=Di encama pêşbirkê de pêşniyara kilînîka '''hematolojiyê''' ya "Agahdariya pirzimanî û mûzîk" serkeftî bû.|www.aa.com.tr/kk 10/2013}} ==== Formên alternatîv ==== * [[hêmatolojî]] === Têkilîdar === * [[hematolog]] * [[hemoglobîn]] ===== Etîmolojî ===== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|hematologie}} * {{Z|sq}}: {{W-|sq|hematologjia|m}} * {{Z|de}}: {{W-|de|Hämatologie|m}} * {{Z|ast}}: {{W-|ast|hematoloxía|m}} * {{Z|az}}: {{W-|az|hematologiya}} * {{Z|eu}}: {{W+|eu|hematologia}} * {{Z|ba}}: {{W-|ba|гематология}} * {{Z|be}}: {{W-|be|гематалогія|m}} * {{Z|bg}}: {{W-|bg|хематология|m}} * {{Z|cs}}: {{W+|cs|hematologie|m}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|血液學|tr=hyut3 jik6 hok6}} *: {{Z|cmn}}: {{W-|cmn|血液學|tr=xuèyèxué}} * {{Z|da}}: {{W-|da|hæmatologi|g}} * {{Z|id}}: {{W+|id|hematologi}} * {{Z|ar}}: {{W-|ar|عِلْم الدَّمْ}} * {{Z|hy}}: {{W+|hy|արյունաբանություն}} * {{Z|eo}}: {{W-|eo|hematologio}} * {{Z|fa}}: {{W-|fa|خون‌شناسی|tr=xun-šenâsi}}, {{W-|fa|هماتولوژی|tr=hemâtoloži}} * {{Z|fi}}: {{W+|fi|hematologia}}, {{W+|fi|veritautioppi}} * {{Z|fr}}: {{W+|fr|hématologie|m}} * {{Z|gl}}: {{W-|gl|hematoloxía|m}} * {{Z|ka}}: {{W-|ka|ჰემატოლოგია}} * {{Z|hi}}: {{W-|hi|रक्तशास्त्र}} * {{Z|nl}}: {{W+|nl|hematologie|m}} * {{Z|io}}: {{W+|io|hematologio}} * {{Z|en}}: {{W+|en|haematology}} * {{Z|ga}}: {{W-|ga|haemaiteolaíocht|m}} * {{Z|it}}: {{W+|it|ematologia|m}} * {{Z|is}}: {{W+|is|blóðfræði|m}} * {{Z|ja}}: {{W-|ja|血液学|tr=けつえきがく, ketsuekigaku|sc=Jpan}} * {{Z|jv}}: {{W-|jv|hematologi}} * {{Z|ca}}: {{W+|ca|hematologia|m}} * {{Z|ky}}: {{W-|ky|гематология}} * {{Z|ko}}: {{W+|ko|혈액학|sc=Kore}} * {{Z|la}}: {{W-|la|haematologia|m}} * {{Z|lv}}: {{W-|lv|hematoloģija|m}} * {{Z|li}}: {{W+|li|bloodslieër|m}} * {{Z|lt}}: {{W-|lt|hematologija|m}} * {{Z|mk}}: {{W-|mk|хематологија|m}} * {{Z|ml}}: {{W-|ml|ഹീമറ്റോളജി}} * {{Z|ms}}: {{W+|ms|hematologi}}, {{W-|ms|kaji darah}} * {{Z|mi}}: {{W-|mi|mātai toto}} * {{Z|hu}}: {{W+|hu|hematológia}} * {{Z|nds}}: *: {{Z|nds-de}}: {{W-|nds-de|Hämatologie|m}} * {{Z|new}}: {{W-|new|हेमाटोलोजी}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|hematologi|n}} *: {{Z|nn}}: {{W-|nn|hematologi|n}} * {{Z|oc}}: {{W-|oc|ematologia|m}} * {{Z|pl}}: {{W+|pl|hematologia|m}} * {{Z|pt}}: {{W+|pt|hematologia|m}} * {{Z|kk}}: {{W-|kk|гематология}} * {{Z|ro}}: {{W+|ro|hematologie|m}} * {{Z|ru}}: {{W+|ru|гематоло́гия|m}} * {{Z|sa}}: {{W-|sa|रक्तशास्त्रम्}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хематоло̀гија|m}} *: Latînî: {{W+|sh|hematològija|m}} * {{Z|sk}}: {{W+|sk|hematológia|m}} * {{Z|sl}}: {{W+|sl|hematologija|m}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|hematologija|m}} *: {{Z|hsb}}: {{W-|hsb|hematologija|m}} * {{Z|es}}: {{W+|es|hematología|m}} * {{Z|sv}}: {{W-|sv|hematologi|g}} * {{Z|tg}}: {{W+|tg|хуншиносӣ}} * {{Z|tl}}: {{W-|tl|paladuguan}}, {{W-|tl|hematolohiya}} * {{Z|th}}: {{W-|th|โลหิตวิทยา|tr=loh-hìt-wít-tá-yaa}} * {{Z|tt}}: {{W-|tt|гематология}} * {{Z|tr}}: {{W+|tr|kan bilimi}}, {{W+|tr|hematoloji}} * {{Z|uk}}: {{W-|uk|гематологія|m}} * Uzbek: *: Kirîlî: {{W+|uz|гематология}} *: Latînî: {{W+|uz|gematologiya}} * {{Z|vi}}: {{W+|vi|huyết học}} * {{Z|war}}: {{W-|war|hematolohiya}} * {{Z|cy}}: {{W-|cy|haematoleg|m}} * {{Z|el}}: {{W+|el|αιματολογία|m}} {{werger-bin}} :{{werger çavkanî|en|haematology|beş=Ev qismê Wergerê|oldid=75897409}} 10hgw1ud59ajhbipjmjgojznkg2cvp5 6291643 6291642 2026-07-27T13:13:54Z Ghybu 1393 6291643 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|hematolojî|mê}} {{navdêr|ku|z=m}} # [[xwînnasî]], [[vekolîn]]ên [[bijîşkî]] li ser [[xwîn]]a [[nexweş]]an #* {{jêder|ku|jêgirtin=Di encama pêşbirkê de pêşniyara kilînîka '''hematolojiyê''' ya "Agahdariya pirzimanî û mûzîk" serkeftî bû.|www.aa.com.tr/kk 10/2013}} ==== Formên alternatîv ==== * [[hêmatolojî]] ==== Têkilîdar ==== * [[hematolog]] * [[hemoglobîn]] ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|hematologie}} * {{Z|sq}}: {{W-|sq|hematologjia|m}} * {{Z|de}}: {{W-|de|Hämatologie|m}} * {{Z|ast}}: {{W-|ast|hematoloxía|m}} * {{Z|az}}: {{W-|az|hematologiya}} * {{Z|eu}}: {{W+|eu|hematologia}} * {{Z|ba}}: {{W-|ba|гематология}} * {{Z|be}}: {{W-|be|гематалогія|m}} * {{Z|bg}}: {{W-|bg|хематология|m}} * {{Z|cs}}: {{W+|cs|hematologie|m}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|血液學|tr=hyut3 jik6 hok6}} *: {{Z|cmn}}: {{W-|cmn|血液學|tr=xuèyèxué}} * {{Z|da}}: {{W-|da|hæmatologi|g}} * {{Z|id}}: {{W+|id|hematologi}} * {{Z|ar}}: {{W-|ar|عِلْم الدَّمْ}} * {{Z|hy}}: {{W+|hy|արյունաբանություն}} * {{Z|eo}}: {{W-|eo|hematologio}} * {{Z|fa}}: {{W-|fa|خون‌شناسی|tr=xun-šenâsi}}, {{W-|fa|هماتولوژی|tr=hemâtoloži}} * {{Z|fi}}: {{W+|fi|hematologia}}, {{W+|fi|veritautioppi}} * {{Z|fr}}: {{W+|fr|hématologie|m}} * {{Z|gl}}: {{W-|gl|hematoloxía|m}} * {{Z|ka}}: {{W-|ka|ჰემატოლოგია}} * {{Z|hi}}: {{W-|hi|रक्तशास्त्र}} * {{Z|nl}}: {{W+|nl|hematologie|m}} * {{Z|io}}: {{W+|io|hematologio}} * {{Z|en}}: {{W+|en|haematology}} * {{Z|ga}}: {{W-|ga|haemaiteolaíocht|m}} * {{Z|it}}: {{W+|it|ematologia|m}} * {{Z|is}}: {{W+|is|blóðfræði|m}} * {{Z|ja}}: {{W-|ja|血液学|tr=けつえきがく, ketsuekigaku|sc=Jpan}} * {{Z|jv}}: {{W-|jv|hematologi}} * {{Z|ca}}: {{W+|ca|hematologia|m}} * {{Z|ky}}: {{W-|ky|гематология}} * {{Z|ko}}: {{W+|ko|혈액학|sc=Kore}} * {{Z|la}}: {{W-|la|haematologia|m}} * {{Z|lv}}: {{W-|lv|hematoloģija|m}} * {{Z|li}}: {{W+|li|bloodslieër|m}} * {{Z|lt}}: {{W-|lt|hematologija|m}} * {{Z|mk}}: {{W-|mk|хематологија|m}} * {{Z|ml}}: {{W-|ml|ഹീമറ്റോളജി}} * {{Z|ms}}: {{W+|ms|hematologi}}, {{W-|ms|kaji darah}} * {{Z|mi}}: {{W-|mi|mātai toto}} * {{Z|hu}}: {{W+|hu|hematológia}} * {{Z|nds}}: *: {{Z|nds-de}}: {{W-|nds-de|Hämatologie|m}} * {{Z|new}}: {{W-|new|हेमाटोलोजी}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|hematologi|n}} *: {{Z|nn}}: {{W-|nn|hematologi|n}} * {{Z|oc}}: {{W-|oc|ematologia|m}} * {{Z|pl}}: {{W+|pl|hematologia|m}} * {{Z|pt}}: {{W+|pt|hematologia|m}} * {{Z|kk}}: {{W-|kk|гематология}} * {{Z|ro}}: {{W+|ro|hematologie|m}} * {{Z|ru}}: {{W+|ru|гематоло́гия|m}} * {{Z|sa}}: {{W-|sa|रक्तशास्त्रम्}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хематоло̀гија|m}} *: Latînî: {{W+|sh|hematològija|m}} * {{Z|sk}}: {{W+|sk|hematológia|m}} * {{Z|sl}}: {{W+|sl|hematologija|m}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|hematologija|m}} *: {{Z|hsb}}: {{W-|hsb|hematologija|m}} * {{Z|es}}: {{W+|es|hematología|m}} * {{Z|sv}}: {{W-|sv|hematologi|g}} * {{Z|tg}}: {{W+|tg|хуншиносӣ}} * {{Z|tl}}: {{W-|tl|paladuguan}}, {{W-|tl|hematolohiya}} * {{Z|th}}: {{W-|th|โลหิตวิทยา|tr=loh-hìt-wít-tá-yaa}} * {{Z|tt}}: {{W-|tt|гематология}} * {{Z|tr}}: {{W+|tr|kan bilimi}}, {{W+|tr|hematoloji}} * {{Z|uk}}: {{W-|uk|гематологія|m}} * Uzbek: *: Kirîlî: {{W+|uz|гематология}} *: Latînî: {{W+|uz|gematologiya}} * {{Z|vi}}: {{W+|vi|huyết học}} * {{Z|war}}: {{W-|war|hematolohiya}} * {{Z|cy}}: {{W-|cy|haematoleg|m}} * {{Z|el}}: {{W+|el|αιματολογία|m}} {{werger-bin}} :{{werger çavkanî|en|haematology|beş=Ev qismê Wergerê|oldid=75897409}} t8uny8n85hf7820thozl3opwnok4kev 6291664 6291643 2026-07-27T15:56:29Z Wikihez 7344 ([[m:Special:MyLanguage/User:Jon Harald Søby/diffedit|diffedit]]) 6291664 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|hematolojî|mê}} {{navdêr|ku|z=m}} # [[xwînnasî]], [[vekolîn]]ên [[bijîşkî]] li ser [[xwîn]]a [[nexweş]]an #* {{jêder|ku|jêgirtin=Di encama pêşbirkê de pêşniyara kilînîka '''hematolojiyê''' ya "Agahdariya pirzimanî û mûzîk" serkeftî bû.|www.aa.com.tr/kk 10/2013}} ==== Formên alternatîv ==== * [[hêmatolojî]] ==== Têkildar ==== * [[hematolog]] * [[hemoglobîn]] ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|hematologie}} * {{Z|sq}}: {{W-|sq|hematologjia|m}} * {{Z|de}}: {{W-|de|Hämatologie|m}} * {{Z|ast}}: {{W-|ast|hematoloxía|m}} * {{Z|az}}: {{W-|az|hematologiya}} * {{Z|eu}}: {{W+|eu|hematologia}} * {{Z|ba}}: {{W-|ba|гематология}} * {{Z|be}}: {{W-|be|гематалогія|m}} * {{Z|bg}}: {{W-|bg|хематология|m}} * {{Z|cs}}: {{W+|cs|hematologie|m}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|血液學|tr=hyut3 jik6 hok6}} *: {{Z|cmn}}: {{W-|cmn|血液學|tr=xuèyèxué}} * {{Z|da}}: {{W-|da|hæmatologi|g}} * {{Z|id}}: {{W+|id|hematologi}} * {{Z|ar}}: {{W-|ar|عِلْم الدَّمْ}} * {{Z|hy}}: {{W+|hy|արյունաբանություն}} * {{Z|eo}}: {{W-|eo|hematologio}} * {{Z|fa}}: {{W-|fa|خون‌شناسی|tr=xun-šenâsi}}, {{W-|fa|هماتولوژی|tr=hemâtoloži}} * {{Z|fi}}: {{W+|fi|hematologia}}, {{W+|fi|veritautioppi}} * {{Z|fr}}: {{W+|fr|hématologie|m}} * {{Z|gl}}: {{W-|gl|hematoloxía|m}} * {{Z|ka}}: {{W-|ka|ჰემატოლოგია}} * {{Z|hi}}: {{W-|hi|रक्तशास्त्र}} * {{Z|nl}}: {{W+|nl|hematologie|m}} * {{Z|io}}: {{W+|io|hematologio}} * {{Z|en}}: {{W+|en|haematology}} * {{Z|ga}}: {{W-|ga|haemaiteolaíocht|m}} * {{Z|it}}: {{W+|it|ematologia|m}} * {{Z|is}}: {{W+|is|blóðfræði|m}} * {{Z|ja}}: {{W-|ja|血液学|tr=けつえきがく, ketsuekigaku|sc=Jpan}} * {{Z|jv}}: {{W-|jv|hematologi}} * {{Z|ca}}: {{W+|ca|hematologia|m}} * {{Z|ky}}: {{W-|ky|гематология}} * {{Z|ko}}: {{W+|ko|혈액학|sc=Kore}} * {{Z|la}}: {{W-|la|haematologia|m}} * {{Z|lv}}: {{W-|lv|hematoloģija|m}} * {{Z|li}}: {{W+|li|bloodslieër|m}} * {{Z|lt}}: {{W-|lt|hematologija|m}} * {{Z|mk}}: {{W-|mk|хематологија|m}} * {{Z|ml}}: {{W-|ml|ഹീമറ്റോളജി}} * {{Z|ms}}: {{W+|ms|hematologi}}, {{W-|ms|kaji darah}} * {{Z|mi}}: {{W-|mi|mātai toto}} * {{Z|hu}}: {{W+|hu|hematológia}} * {{Z|nds}}: *: {{Z|nds-de}}: {{W-|nds-de|Hämatologie|m}} * {{Z|new}}: {{W-|new|हेमाटोलोजी}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|hematologi|n}} *: {{Z|nn}}: {{W-|nn|hematologi|n}} * {{Z|oc}}: {{W-|oc|ematologia|m}} * {{Z|pl}}: {{W+|pl|hematologia|m}} * {{Z|pt}}: {{W+|pt|hematologia|m}} * {{Z|kk}}: {{W-|kk|гематология}} * {{Z|ro}}: {{W+|ro|hematologie|m}} * {{Z|ru}}: {{W+|ru|гематоло́гия|m}} * {{Z|sa}}: {{W-|sa|रक्तशास्त्रम्}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хематоло̀гија|m}} *: Latînî: {{W+|sh|hematològija|m}} * {{Z|sk}}: {{W+|sk|hematológia|m}} * {{Z|sl}}: {{W+|sl|hematologija|m}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|hematologija|m}} *: {{Z|hsb}}: {{W-|hsb|hematologija|m}} * {{Z|es}}: {{W+|es|hematología|m}} * {{Z|sv}}: {{W-|sv|hematologi|g}} * {{Z|tg}}: {{W+|tg|хуншиносӣ}} * {{Z|tl}}: {{W-|tl|paladuguan}}, {{W-|tl|hematolohiya}} * {{Z|th}}: {{W-|th|โลหิตวิทยา|tr=loh-hìt-wít-tá-yaa}} * {{Z|tt}}: {{W-|tt|гематология}} * {{Z|tr}}: {{W+|tr|kan bilimi}}, {{W+|tr|hematoloji}} * {{Z|uk}}: {{W-|uk|гематологія|m}} * Uzbek: *: Kirîlî: {{W+|uz|гематология}} *: Latînî: {{W+|uz|gematologiya}} * {{Z|vi}}: {{W+|vi|huyết học}} * {{Z|war}}: {{W-|war|hematolohiya}} * {{Z|cy}}: {{W-|cy|haematoleg|m}} * {{Z|el}}: {{W+|el|αιματολογία|m}} {{werger-bin}} :{{werger çavkanî|en|haematology|beş=Ev qismê Wergerê|oldid=75897409}} lp5535nb5f30m8lmmiqubpayondulvx 6291665 6291664 2026-07-27T15:57:37Z Wikihez 7344 [[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin 6291665 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|hematolojî|mê}} {{navdêr|ku|z=m}} # {{e|ku|ilm}} [[vekolîn|Vekolîn]]ên [[bijîşkî]] li ser [[xwîn]]a [[nexweş]]an. #: {{hevmane|ku|xwînnasî}} #* {{jêder|ku|jêgirtin=Di encama pêşbirkê de pêşniyara kilînîka '''hematolojiyê''' ya "Agahdariya pirzimanî û mûzîk" serkeftî bû.|www.aa.com.tr/kk 10/2013}} ==== Formên alternatîv ==== * {{g|ku|hêmatolojî}} ==== Têkildar ==== * {{g|ku|hematolog}} * {{g|ku|hemoglobîn}} ==== Etîmolojî ==== Ji {{ji|en|ku|haematology}}. ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|hematologie}} * {{Z|sq}}: {{W-|sq|hematologjia|m}} * {{Z|de}}: {{W-|de|Hämatologie|m}} * {{Z|ast}}: {{W-|ast|hematoloxía|m}} * {{Z|az}}: {{W-|az|hematologiya}} * {{Z|eu}}: {{W+|eu|hematologia}} * {{Z|ba}}: {{W-|ba|гематология}} * {{Z|be}}: {{W-|be|гематалогія|m}} * {{Z|bg}}: {{W-|bg|хематология|m}} * {{Z|cs}}: {{W+|cs|hematologie|m}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|血液學|tr=hyut3 jik6 hok6}} *: {{Z|cmn}}: {{W-|cmn|血液學|tr=xuèyèxué}} * {{Z|da}}: {{W-|da|hæmatologi|g}} * {{Z|id}}: {{W+|id|hematologi}} * {{Z|ar}}: {{W-|ar|عِلْم الدَّمْ}} * {{Z|hy}}: {{W+|hy|արյունաբանություն}} * {{Z|eo}}: {{W-|eo|hematologio}} * {{Z|fa}}: {{W-|fa|خون‌شناسی|tr=xun-šenâsi}}, {{W-|fa|هماتولوژی|tr=hemâtoloži}} * {{Z|fi}}: {{W+|fi|hematologia}}, {{W+|fi|veritautioppi}} * {{Z|fr}}: {{W+|fr|hématologie|m}} * {{Z|gl}}: {{W-|gl|hematoloxía|m}} * {{Z|ka}}: {{W-|ka|ჰემატოლოგია}} * {{Z|hi}}: {{W-|hi|रक्तशास्त्र}} * {{Z|nl}}: {{W+|nl|hematologie|m}} * {{Z|io}}: {{W+|io|hematologio}} * {{Z|en}}: {{W+|en|haematology}} * {{Z|ga}}: {{W-|ga|haemaiteolaíocht|m}} * {{Z|it}}: {{W+|it|ematologia|m}} * {{Z|is}}: {{W+|is|blóðfræði|m}} * {{Z|ja}}: {{W-|ja|血液学|tr=けつえきがく, ketsuekigaku|sc=Jpan}} * {{Z|jv}}: {{W-|jv|hematologi}} * {{Z|ca}}: {{W+|ca|hematologia|m}} * {{Z|ky}}: {{W-|ky|гематология}} * {{Z|ko}}: {{W+|ko|혈액학|sc=Kore}} * {{Z|la}}: {{W-|la|haematologia|m}} * {{Z|lv}}: {{W-|lv|hematoloģija|m}} * {{Z|li}}: {{W+|li|bloodslieër|m}} * {{Z|lt}}: {{W-|lt|hematologija|m}} * {{Z|mk}}: {{W-|mk|хематологија|m}} * {{Z|ml}}: {{W-|ml|ഹീമറ്റോളജി}} * {{Z|ms}}: {{W+|ms|hematologi}}, {{W-|ms|kaji darah}} * {{Z|mi}}: {{W-|mi|mātai toto}} * {{Z|hu}}: {{W+|hu|hematológia}} * {{Z|nds}}: *: {{Z|nds-de}}: {{W-|nds-de|Hämatologie|m}} * {{Z|new}}: {{W-|new|हेमाटोलोजी}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|hematologi|n}} *: {{Z|nn}}: {{W-|nn|hematologi|n}} * {{Z|oc}}: {{W-|oc|ematologia|m}} * {{Z|pl}}: {{W+|pl|hematologia|m}} * {{Z|pt}}: {{W+|pt|hematologia|m}} * {{Z|kk}}: {{W-|kk|гематология}} * {{Z|ro}}: {{W+|ro|hematologie|m}} * {{Z|ru}}: {{W+|ru|гематоло́гия|m}} * {{Z|sa}}: {{W-|sa|रक्तशास्त्रम्}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хематоло̀гија|m}} *: Latînî: {{W+|sh|hematològija|m}} * {{Z|sk}}: {{W+|sk|hematológia|m}} * {{Z|sl}}: {{W+|sl|hematologija|m}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|hematologija|m}} *: {{Z|hsb}}: {{W-|hsb|hematologija|m}} * {{Z|es}}: {{W+|es|hematología|m}} * {{Z|sv}}: {{W-|sv|hematologi|g}} * {{Z|tg}}: {{W+|tg|хуншиносӣ}} * {{Z|tl}}: {{W-|tl|paladuguan}}, {{W-|tl|hematolohiya}} * {{Z|th}}: {{W-|th|โลหิตวิทยา|tr=loh-hìt-wít-tá-yaa}} * {{Z|tt}}: {{W-|tt|гематология}} * {{Z|tr}}: {{W+|tr|kan bilimi}}, {{W+|tr|hematoloji}} * {{Z|uk}}: {{W-|uk|гематологія|m}} * Uzbek: *: Kirîlî: {{W+|uz|гематология}} *: Latînî: {{W+|uz|gematologiya}} * {{Z|vi}}: {{W+|vi|huyết học}} * {{Z|war}}: {{W-|war|hematolohiya}} * {{Z|cy}}: {{W-|cy|haematoleg|m}} * {{Z|el}}: {{W+|el|αιματολογία|m}} {{werger-bin}} :{{werger çavkanî|en|haematology|beş=Ev qismê Wergerê|oldid=75897409}} mqc8htocuiix1coc0f7ulho55kh19hs 6291666 6291665 2026-07-27T15:58:04Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291666 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|hematolojî|mê}} {{navdêr|ku|z=m}} # {{e|ku|ilm}} [[vekolîn|Vekolîn]]ên [[bijîşkî]] li ser [[xwîn]]a [[nexweş]]an. #: {{hevmane|ku|xwînnasî}} #* {{jêder-websîte|ku|jêgirtin=Di encama pêşbirkê de pêşniyara kilînîka '''hematolojiyê''' ya "Agahdariya pirzimanî û mûzîk" serkeftî bû.|websîte=www.aa.com.tr/kk|sal=10/2013}} ==== Formên alternatîv ==== * {{g|ku|hêmatolojî}} ==== Têkildar ==== * {{g|ku|hematolog}} * {{g|ku|hemoglobîn}} ==== Etîmolojî ==== Ji {{ji|en|ku|haematology}}. ==== Werger ==== {{werger-ser}} * {{Z|af}}: {{W-|af|hematologie}} * {{Z|sq}}: {{W-|sq|hematologjia|m}} * {{Z|de}}: {{W-|de|Hämatologie|m}} * {{Z|ast}}: {{W-|ast|hematoloxía|m}} * {{Z|az}}: {{W-|az|hematologiya}} * {{Z|eu}}: {{W+|eu|hematologia}} * {{Z|ba}}: {{W-|ba|гематология}} * {{Z|be}}: {{W-|be|гематалогія|m}} * {{Z|bg}}: {{W-|bg|хематология|m}} * {{Z|cs}}: {{W+|cs|hematologie|m}} * {{Z|zh}}: *: {{Z|yue}}: {{W-|yue|血液學|tr=hyut3 jik6 hok6}} *: {{Z|cmn}}: {{W-|cmn|血液學|tr=xuèyèxué}} * {{Z|da}}: {{W-|da|hæmatologi|g}} * {{Z|id}}: {{W+|id|hematologi}} * {{Z|ar}}: {{W-|ar|عِلْم الدَّمْ}} * {{Z|hy}}: {{W+|hy|արյունաբանություն}} * {{Z|eo}}: {{W-|eo|hematologio}} * {{Z|fa}}: {{W-|fa|خون‌شناسی|tr=xun-šenâsi}}, {{W-|fa|هماتولوژی|tr=hemâtoloži}} * {{Z|fi}}: {{W+|fi|hematologia}}, {{W+|fi|veritautioppi}} * {{Z|fr}}: {{W+|fr|hématologie|m}} * {{Z|gl}}: {{W-|gl|hematoloxía|m}} * {{Z|ka}}: {{W-|ka|ჰემატოლოგია}} * {{Z|hi}}: {{W-|hi|रक्तशास्त्र}} * {{Z|nl}}: {{W+|nl|hematologie|m}} * {{Z|io}}: {{W+|io|hematologio}} * {{Z|en}}: {{W+|en|haematology}} * {{Z|ga}}: {{W-|ga|haemaiteolaíocht|m}} * {{Z|it}}: {{W+|it|ematologia|m}} * {{Z|is}}: {{W+|is|blóðfræði|m}} * {{Z|ja}}: {{W-|ja|血液学|tr=けつえきがく, ketsuekigaku|sc=Jpan}} * {{Z|jv}}: {{W-|jv|hematologi}} * {{Z|ca}}: {{W+|ca|hematologia|m}} * {{Z|ky}}: {{W-|ky|гематология}} * {{Z|ko}}: {{W+|ko|혈액학|sc=Kore}} * {{Z|la}}: {{W-|la|haematologia|m}} * {{Z|lv}}: {{W-|lv|hematoloģija|m}} * {{Z|li}}: {{W+|li|bloodslieër|m}} * {{Z|lt}}: {{W-|lt|hematologija|m}} * {{Z|mk}}: {{W-|mk|хематологија|m}} * {{Z|ml}}: {{W-|ml|ഹീമറ്റോളജി}} * {{Z|ms}}: {{W+|ms|hematologi}}, {{W-|ms|kaji darah}} * {{Z|mi}}: {{W-|mi|mātai toto}} * {{Z|hu}}: {{W+|hu|hematológia}} * {{Z|nds}}: *: {{Z|nds-de}}: {{W-|nds-de|Hämatologie|m}} * {{Z|new}}: {{W-|new|हेमाटोलोजी}} * {{Z|no}}: *: {{Z|nb}}: {{W-|nb|hematologi|n}} *: {{Z|nn}}: {{W-|nn|hematologi|n}} * {{Z|oc}}: {{W-|oc|ematologia|m}} * {{Z|pl}}: {{W+|pl|hematologia|m}} * {{Z|pt}}: {{W+|pt|hematologia|m}} * {{Z|kk}}: {{W-|kk|гематология}} * {{Z|ro}}: {{W+|ro|hematologie|m}} * {{Z|ru}}: {{W+|ru|гематоло́гия|m}} * {{Z|sa}}: {{W-|sa|रक्तशास्त्रम्}} * {{Z|sh}}: *: Kirîlî: {{W-|sh|хематоло̀гија|m}} *: Latînî: {{W+|sh|hematològija|m}} * {{Z|sk}}: {{W+|sk|hematológia|m}} * {{Z|sl}}: {{W+|sl|hematologija|m}} * Sorbî: *: {{Z|dsb}}: {{W-|dsb|hematologija|m}} *: {{Z|hsb}}: {{W-|hsb|hematologija|m}} * {{Z|es}}: {{W+|es|hematología|m}} * {{Z|sv}}: {{W-|sv|hematologi|g}} * {{Z|tg}}: {{W+|tg|хуншиносӣ}} * {{Z|tl}}: {{W-|tl|paladuguan}}, {{W-|tl|hematolohiya}} * {{Z|th}}: {{W-|th|โลหิตวิทยา|tr=loh-hìt-wít-tá-yaa}} * {{Z|tt}}: {{W-|tt|гематология}} * {{Z|tr}}: {{W+|tr|kan bilimi}}, {{W+|tr|hematoloji}} * {{Z|uk}}: {{W-|uk|гематологія|m}} * Uzbek: *: Kirîlî: {{W+|uz|гематология}} *: Latînî: {{W+|uz|gematologiya}} * {{Z|vi}}: {{W+|vi|huyết học}} * {{Z|war}}: {{W-|war|hematolohiya}} * {{Z|cy}}: {{W-|cy|haematoleg|m}} * {{Z|el}}: {{W+|el|αιματολογία|m}} {{werger-bin}} :{{werger çavkanî|en|haematology|beş=Ev qismê Wergerê|oldid=75897409}} ayxxbd8nh54axdthzn6z9nm0t4wltmt Sufi 0 312605 6291747 5724184 2026-07-27T23:12:11Z Wikihez 7344 /* Navdêr */ 6291747 wikitext text/x-wiki == {{ziman|en}} == === Navdêr === {{navdêr|en}} # [[sofî]], [[mutesewif]] 9tgjgxf5kge7euya6r79tvgjx0obr4h Şablon:bêçavkanî 10 448836 6291817 6291615 2026-07-28T06:10:22Z Wikihez 7344 Restored revision 4856770 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291817 wikitext text/x-wiki {{hişyarî | rengê hundir = white | rengê sîndorî = #C00 | rengê sîndorê çep = #C00 | wêne = Question_book-new.svg | nivîs = {{reng2|#C00|'''Çavkaniya vê peyvê tune ye û ji ber wê peyitandina agahiyan ne mimkin e.'''}} | nivîsa jêr = <small>Ji bo başkirina vê peyvê ji kerema xwe re çavkaniyan pê ve bike. Herwiha binêre gotûbêja li [[Wîkîferheng:Daxwazên peyitandinê#{{FULLPAGENAME}}|Wîkîferheng:Daxwazên peyitandinê]].<sup class="plainlinks" style="font-weight:normal" title="Li Daxwazên peyitandinê zêde bike"> (<!-- -->[{{fullurle:Wîkîferheng:Daxwazên peyitandinê|action=edit&section=new&preload=Şablon:p-wate/preload&preloadtitle=%5B%5B{{urlencode:{{FULLPAGENAME}}}}}}%5D%5D +]<!-- -->)</sup></small><br/>{{çavkanî bigere}} }}{{#tag:indicator|[[Wêne:Question_book-new.svg|25px|Gotarên bêçavkanî|link={{#if:{{{ziman|}}}|{{PAGENAME}}#{{ucfirst:{{nav ziman|{{{ziman|}}}}}}}|Kategorî:Gotarên bêçavkanî}}]]|name=Bêçavkanî}}<includeonly>[[Kategorî:Gotarên bêçavkanî]]</includeonly><noinclude> {{belgekirin}} </noinclude> 8g4tblnttr46y5gm5jc37nzdat3bjvv 6291818 6291817 2026-07-28T06:10:44Z Wikihez 7344 Restored revision 6117825 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291818 wikitext text/x-wiki {{hişyarî | rengê hundir = white | rengê sîndorî = #C00 | rengê sîndorê çep = #C00 | wêne = Question_book-new.svg | nivîs = {{reng2|#C00|'''Çavkaniya vê madeyê tine ye û ji ber wê peyitandina malûmatan ne mimkin e.'''}} | nivîsa jêr = <small>Ji bo başkirina vê madeyê ji kerema xwe re çavkaniyan pê ve bike. Herwiha binêre gotûbêja li [[Wîkîferheng:Daxwazên peyitandinê#{{FULLPAGENAME}}|Wîkîferheng:Daxwazên peyitandinê]].<sup class="plainlinks" style="font-weight:normal" title="Li Daxwazên peyitandinê zêde bike"> (<!-- -->[{{fullurle:Wîkîferheng:Daxwazên peyitandinê|action=edit&section=new&preload=Şablon:p-wate/preload&preloadtitle=%5B%5B{{urlencode:{{FULLPAGENAME}}}}}}%5D%5D +]<!-- -->)</sup></small><br/>{{çavkanî bigere}} }}{{#tag:indicator|[[Wêne:Question_book-new.svg|25px|Gotarên bêçavkanî|link={{#if:{{{ziman|}}}|{{PAGENAME}}#{{ucfirst:{{nav ziman|{{{ziman|}}}}}}}|Kategorî:Madeyên bêçavkanî}}]]|name=Bêçavkanî}}<includeonly>[[Kategorî:Madeyên bêçavkanî]]</includeonly><noinclude> {{belgekirin}} </noinclude> 9908i4vz9c3xwy00l5lsv9pzzkp0zdp dutayî 0 535871 6291652 5830593 2026-07-27T14:28:19Z Keyomerd 8814 /* Kurmancî */ 6291652 wikitext text/x-wiki == {{ziman|ku}} == === Navdêr === {{navdêr|ku|z=m}} # [[duqat]], [[dubleks]] # {{f|ku|zimannasî}} [[peyv|Peyvên]] di [[ziman|zimanekî]] de ku [[rehnasî|rehnasiya]] wan yek be lê yek ji wan deynkirî be. ==== Etîmolojî ==== Ji {{heve|ku|du|ta|-yî}}. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W+|tr|dubleks}} {{werger-bin}} {{kontrol}} sa26tjo666cq7l2y4tpfwgvtc3a14s4 6291653 6291652 2026-07-27T14:30:25Z Keyomerd 8814 /* Navdêr */ 6291653 wikitext text/x-wiki == {{ziman|ku}} == === Navdêr === {{navdêr|ku|z=m}} # [[duqat]], [[dubleks]] # {{f|ku|zimannasî}} [[peyv|Peyvên]] di [[ziman|zimanekî]] de ku [[rehnasî|rehnasiya]] wan yek be lê yek ji wan deynkirî be. {{examples|sense=zimannasî|examples= *Zerya û derya *Hinav û endam }} ==== Etîmolojî ==== Ji {{heve|ku|du|ta|-yî}}. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W+|tr|dubleks}} {{werger-bin}} {{kontrol}} koyocetot12dlnnyvlpu4optcthnewg 6291654 6291653 2026-07-27T14:35:22Z Wikihez 7344 Guhartinên [[Special:Contributions/Keyomerd|Keyomerd]] ([[User talk:Keyomerd|gotûbêj]]) hatine betalkirin, vegerand guhartoya dawî ya [[User:Balyozbot|Balyozbot]] 5830593 wikitext text/x-wiki == {{ziman|ku}} == === Mane === {{cure?|ku}} # [[duqat]], [[dubleks]] ==== Etîmolojî ==== Ji {{qertaf|ku|du|tayî}}. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W+|tr|dubleks}} {{werger-bin}} {{kontrol}} fs5jp8jveowyqgnc4viqsf69pebotxk 6291655 6291654 2026-07-27T14:35:37Z Wikihez 7344 Guhartinên [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|gotûbêj]]) hatine betalkirin, vegerand guhartoya dawî ya [[User:Keyomerd|Keyomerd]] 6291653 wikitext text/x-wiki == {{ziman|ku}} == === Navdêr === {{navdêr|ku|z=m}} # [[duqat]], [[dubleks]] # {{f|ku|zimannasî}} [[peyv|Peyvên]] di [[ziman|zimanekî]] de ku [[rehnasî|rehnasiya]] wan yek be lê yek ji wan deynkirî be. {{examples|sense=zimannasî|examples= *Zerya û derya *Hinav û endam }} ==== Etîmolojî ==== Ji {{heve|ku|du|ta|-yî}}. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W+|tr|dubleks}} {{werger-bin}} {{kontrol}} koyocetot12dlnnyvlpu4optcthnewg 6291658 6291655 2026-07-27T14:54:56Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291658 wikitext text/x-wiki == {{ziman|ku}} == === Navdêr === {{navdêr|ku|z=m}} # [[duqat]], [[dubleks]] ==== Etîmolojî ==== Ji {{heve|ku|du|ta|-yî}}. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W+|tr|dubleks}} {{werger-bin}} {{kontrol}} sdvqwcrkbyar8qykkm2fe5d0yxiwvhm 6291677 6291658 2026-07-27T17:11:37Z Wikihez 7344 [[Bikarhêner:Wikihez/templateScript2.js|TS]]: sererastkirin 6291677 wikitext text/x-wiki == {{ziman|ku}} == === Rengdêr === {{rengdêr|ku}} # Yê bi du [[qat|qatî]]. #: {{hevmane|ku|duqat|dubleks}} ==== Etîmolojî ==== Ji {{heve|ku|du|ta|-yî}}. ==== Werger ==== {{werger-ser}} * {{Z|tr}}: {{W+|tr|dubleks}}, {{W+|tr|iki katlı}} {{werger-bin}} 0way7km005h8fikfg7wc0iqrr6bblzw Beytullah 0 536491 6291753 6278339 2026-07-27T23:18:25Z Wikihez 7344 /* {{ziman|ku}} */ 6291753 wikitext text/x-wiki == {{ziman|ku}} == === Serenav === {{serenav|ku}} # {{e|ku|Îslam}} [[Ke'be]] ==== Etîmolojî ==== {{bêetîmolojî|ku}} ==== Werger ==== {{werger-ser}} * {{Z|en}}: {{W+|en|Kaaba}} * {{Z|tr}}: {{W-|tr|kâbe}} {{werger-bin}} bl17hzmir5j86jifrv5xthuapzoiv4g dayak kaçkını 0 609352 6291812 2509008 2026-07-28T05:38:20Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +tr:navdêr: 6291812 wikitext text/x-wiki == {{ziman|tr}} == === Navdêr === {{navdêr|tr}} # {{hevmaneya|tr|dayak düşkünü}} 8p1vxafl42fg7yrqbrs39u48ma78xhb face up 0 638095 6291800 5733884 2026-07-28T02:38:29Z Wikihez 7344 6291800 wikitext text/x-wiki == {{ziman|en}} == === Lêker === {{lêker|en}} #[[beramberî|beramberî]] [[seqfî|seqfî]] [[bûn|bûn]] #: {{nm|en|his face was face up.|Navçavê wi beramberi seqfî bû.}} t2gi15dijavsmh2to7j8uih8vum27ea 6291801 6291800 2026-07-28T02:39:04Z Wikihez 7344 6291801 wikitext text/x-wiki == {{ziman|en}} == === Lêker === {{lêker|en}} #[[beramberî|beramberî]] [[seqfî|seqfî]] [[bûn|bûn]] #: {{nm|en|his face was '''face up'''.|Navçavê wi beramberi seqfî bû.}} 276b7ge6v6gx5osazxekuoof6aycntn Modul:ku-tewîn-nav 828 652549 6291759 6276387 2026-07-27T23:27:42Z Ghybu 1393 alt.çem.yj: zêde dike/ "çem.yj" dikeve şûn 6291759 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function genderTable(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end local function formsTab(forms, sep) forms = mw.text.split(forms, ';') for i, v in ipairs(forms) do forms[i] = v end if sep then sep = sep else sep = ', ' end return table.concat(forms, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local flexTab = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. flexTab['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=flexTab["defSg"]} ..'\n|' .. link{lang=langKu, term=flexTab["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=flexTab["indefSg"]} ..'\n|' .. link{lang=langKu, term=flexTab["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local flexTabAlt1 = export.declSimpleNoun{noun, gender, alt='1'} local flexTabAlt2 = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then flexTabAlt1["vocSg"] = formsTab(args['bang.yj']) flexTabAlt2["vocSg"] = formsTab(args['bang.yj']) end if vocPl then flexTabAlt1["vocPl"] = formsTab(args['bang.pj']) flexTabAlt2["vocPl"] = formsTab(args['bang.pj']) end if defOblSg then flexTabAlt1["defOblSg"] = formsTab(args['çem.yj']) flexTabAlt2["defOblSg"] = formsTab(args['çem.yj']) elseif altDefOblSg then flexTabAlt1["defOblSg"] = flexTabAlt1["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} flexTabAlt2["defOblSg"] = flexTabAlt2["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function flexTab(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return flexTabAlt1[case] else return flexTabAlt1[case] .. '<br>' .. flexTabAlt2[case] end elseif alt == '2' then return flexTabAlt2[case] else return flexTabAlt1[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. genderTable(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. flexTabAlt1["defNomSg"] ..'\n|' .. flexTabAlt1["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. flexTab("defConstrSg") ..'\n|' .. flexTab("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. flexTab("defOblSg") ..'\n|' .. flexTab("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. flexTab("defDemonsOblSg") ..'\n|' .. flexTab("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. flexTab("vocSg") ..'\n|' .. flexTab("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. genderTable(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. flexTab("indefNomSg") ..'\n|' .. flexTab("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. flexTab("indefConstrSg") ..'\n|' .. flexTab("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. flexTab("indefOblSg") ..'\n|' .. flexTab("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn, mk.: -- 1. {{#invoke:ku-tewîn-nav|tew|pos=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|pos=indefConstrSg}} -- Ji bo tabloyên formên navdêran: [[Şablon:ku-tewîn-navForm]] -- Bnr. [[sêva]], [[sêvê]], [[hevala]], [[hevalê]] -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export 88s9zku8g2i4avq8shyej2t4vfbqeep 6291769 6291759 2026-07-28T00:53:36Z Ghybu 1393 nav 6291769 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function genderTable(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end --- Converts a semicolon-separated list of forms into a formatted string. --- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = mw.text.trim(v) end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local flexTab = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. flexTab['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=flexTab["defSg"]} ..'\n|' .. link{lang=langKu, term=flexTab["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=flexTab["indefSg"]} ..'\n|' .. link{lang=langKu, term=flexTab["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local flexTabAlt1 = export.declSimpleNoun{noun, gender, alt='1'} local flexTabAlt2 = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then flexTabAlt1["vocSg"] = formatForms(args['bang.yj']) flexTabAlt2["vocSg"] = formatForms(args['bang.yj']) end if vocPl then flexTabAlt1["vocPl"] = formatForms(args['bang.pj']) flexTabAlt2["vocPl"] = formatForms(args['bang.pj']) end if defOblSg then flexTabAlt1["defOblSg"] = formatForms(args['çem.yj']) flexTabAlt2["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then flexTabAlt1["defOblSg"] = flexTabAlt1["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} flexTabAlt2["defOblSg"] = flexTabAlt2["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function flexTab(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return flexTabAlt1[case] else return flexTabAlt1[case] .. '<br>' .. flexTabAlt2[case] end elseif alt == '2' then return flexTabAlt2[case] else return flexTabAlt1[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. genderTable(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. flexTabAlt1["defNomSg"] ..'\n|' .. flexTabAlt1["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. flexTab("defConstrSg") ..'\n|' .. flexTab("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. flexTab("defOblSg") ..'\n|' .. flexTab("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. flexTab("defDemonsOblSg") ..'\n|' .. flexTab("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. flexTab("vocSg") ..'\n|' .. flexTab("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. genderTable(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. flexTab("indefNomSg") ..'\n|' .. flexTab("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. flexTab("indefConstrSg") ..'\n|' .. flexTab("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. flexTab("indefOblSg") ..'\n|' .. flexTab("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn, mk.: -- 1. {{#invoke:ku-tewîn-nav|tew|pos=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|pos=indefConstrSg}} -- Ji bo tabloyên formên navdêran: [[Şablon:ku-tewîn-navForm]] -- Bnr. [[sêva]], [[sêvê]], [[hevala]], [[hevalê]] -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export blzpqbve6rakvnfxzuzroapa87itswy 6291770 6291769 2026-07-28T00:58:57Z Ghybu 1393 nav 6291770 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end --- Converts a semicolon-separated list of forms into a formatted string. --- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = mw.text.trim(v) end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local flexTab = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. flexTab['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=flexTab["defSg"]} ..'\n|' .. link{lang=langKu, term=flexTab["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=flexTab["indefSg"]} ..'\n|' .. link{lang=langKu, term=flexTab["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local flexTabAlt1 = export.declSimpleNoun{noun, gender, alt='1'} local flexTabAlt2 = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then flexTabAlt1["vocSg"] = formatForms(args['bang.yj']) flexTabAlt2["vocSg"] = formatForms(args['bang.yj']) end if vocPl then flexTabAlt1["vocPl"] = formatForms(args['bang.pj']) flexTabAlt2["vocPl"] = formatForms(args['bang.pj']) end if defOblSg then flexTabAlt1["defOblSg"] = formatForms(args['çem.yj']) flexTabAlt2["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then flexTabAlt1["defOblSg"] = flexTabAlt1["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} flexTabAlt2["defOblSg"] = flexTabAlt2["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function flexTab(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return flexTabAlt1[case] else return flexTabAlt1[case] .. '<br>' .. flexTabAlt2[case] end elseif alt == '2' then return flexTabAlt2[case] else return flexTabAlt1[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. flexTabAlt1["defNomSg"] ..'\n|' .. flexTabAlt1["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. flexTab("defConstrSg") ..'\n|' .. flexTab("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. flexTab("defOblSg") ..'\n|' .. flexTab("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. flexTab("defDemonsOblSg") ..'\n|' .. flexTab("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. flexTab("vocSg") ..'\n|' .. flexTab("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. flexTab("indefNomSg") ..'\n|' .. flexTab("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. flexTab("indefConstrSg") ..'\n|' .. flexTab("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. flexTab("indefOblSg") ..'\n|' .. flexTab("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn, mk.: -- 1. {{#invoke:ku-tewîn-nav|tew|pos=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|pos=indefConstrSg}} -- Ji bo tabloyên formên navdêran: [[Şablon:ku-tewîn-navForm]] -- Bnr. [[sêva]], [[sêvê]], [[hevala]], [[hevalê]] -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export l4n1pblwdrnu4bbvqgkywezox0oaknm 6291771 6291770 2026-07-28T01:35:44Z Ghybu 1393 nav 6291771 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end --- Converts a semicolon-separated list of forms into a formatted string. --- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = mw.text.trim(v) end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local getDeclinedForm = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. getDeclinedForm['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=getDeclinedForm["defSg"]} ..'\n|' .. link{lang=langKu, term=getDeclinedForm["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=getDeclinedForm["indefSg"]} ..'\n|' .. link{lang=langKu, term=getDeclinedForm["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local declSimpleNoun = export.declSimpleNoun{noun, gender} local altDeclSimpleNoun = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then declSimpleNoun["vocSg"] = formatForms(args['bang.yj']) altDeclSimpleNoun["vocSg"] = formatForms(args['bang.yj']) end if vocPl then declSimpleNoun["vocPl"] = formatForms(args['bang.pj']) altDeclSimpleNoun["vocPl"] = formatForms(args['bang.pj']) end if defOblSg then declSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) altDeclSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then declSimpleNoun["defOblSg"] = declSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} altDeclSimpleNoun["defOblSg"] = altDeclSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function getDeclinedForm(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return declSimpleNoun[case] else return declSimpleNoun[case] .. '<br>' .. altDeclSimpleNoun[case] end elseif alt == '2' then return altDeclSimpleNoun[case] else return declSimpleNoun[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. declSimpleNoun["defNomSg"] ..'\n|' .. declSimpleNoun["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("defConstrSg") ..'\n|' .. getDeclinedForm("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("defOblSg") ..'\n|' .. getDeclinedForm("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. getDeclinedForm("defDemonsOblSg") ..'\n|' .. getDeclinedForm("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. getDeclinedForm("vocSg") ..'\n|' .. getDeclinedForm("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. getDeclinedForm("indefNomSg") ..'\n|' .. getDeclinedForm("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("indefConstrSg") ..'\n|' .. getDeclinedForm("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("indefOblSg") ..'\n|' .. getDeclinedForm("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn, mk.: -- 1. {{#invoke:ku-tewîn-nav|tew|pos=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|pos=indefConstrSg}} -- Ji bo tabloyên formên navdêran: [[Şablon:ku-tewîn-navForm]] -- Bnr. [[sêva]], [[sêvê]], [[hevala]], [[hevalê]] -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export njm8ij0h13yndm4pp64sqnccnamg3b2 6291774 6291771 2026-07-28T01:42:35Z Ghybu 1393 6291774 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end -- Converts a semicolon-separated list of forms into a formatted string. -- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = mw.text.trim(v) end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local getDeclinedForm = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. getDeclinedForm['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=getDeclinedForm["defSg"]} ..'\n|' .. link{lang=langKu, term=getDeclinedForm["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=getDeclinedForm["indefSg"]} ..'\n|' .. link{lang=langKu, term=getDeclinedForm["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local declSimpleNoun = export.declSimpleNoun{noun, gender} local altDeclSimpleNoun = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then declSimpleNoun["vocSg"] = formatForms(args['bang.yj']) altDeclSimpleNoun["vocSg"] = formatForms(args['bang.yj']) end if vocPl then declSimpleNoun["vocPl"] = formatForms(args['bang.pj']) altDeclSimpleNoun["vocPl"] = formatForms(args['bang.pj']) end if defOblSg then declSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) altDeclSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then declSimpleNoun["defOblSg"] = declSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} altDeclSimpleNoun["defOblSg"] = altDeclSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function getDeclinedForm(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return declSimpleNoun[case] else return declSimpleNoun[case] .. '<br>' .. altDeclSimpleNoun[case] end elseif alt == '2' then return altDeclSimpleNoun[case] else return declSimpleNoun[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. declSimpleNoun["defNomSg"] ..'\n|' .. declSimpleNoun["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("defConstrSg") ..'\n|' .. getDeclinedForm("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("defOblSg") ..'\n|' .. getDeclinedForm("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. getDeclinedForm("defDemonsOblSg") ..'\n|' .. getDeclinedForm("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. getDeclinedForm("vocSg") ..'\n|' .. getDeclinedForm("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. getDeclinedForm("indefNomSg") ..'\n|' .. getDeclinedForm("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("indefConstrSg") ..'\n|' .. getDeclinedForm("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("indefOblSg") ..'\n|' .. getDeclinedForm("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn, mk.: -- 1. {{#invoke:ku-tewîn-nav|tew|pos=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|pos=indefConstrSg}} -- Ji bo tabloyên formên navdêran: [[Şablon:ku-tewîn-navForm]] -- Bnr. [[sêva]], [[sêvê]], [[hevala]], [[hevalê]] -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export 6yuto9dikvhgeqfcnu50ljqltij9qjj 6291776 6291774 2026-07-28T01:51:44Z Ghybu 1393 nav 6291776 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end -- Converts a semicolon-separated list of forms into a formatted string. -- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = mw.text.trim(v) end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local declCompoundNoun = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. declCompoundNoun['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local declSimpleNoun = export.declSimpleNoun{noun, gender} local altDeclSimpleNoun = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then declSimpleNoun["vocSg"] = formatForms(args['bang.yj']) altDeclSimpleNoun["vocSg"] = formatForms(args['bang.yj']) end if vocPl then declSimpleNoun["vocPl"] = formatForms(args['bang.pj']) altDeclSimpleNoun["vocPl"] = formatForms(args['bang.pj']) end if defOblSg then declSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) altDeclSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then declSimpleNoun["defOblSg"] = declSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} altDeclSimpleNoun["defOblSg"] = altDeclSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function getDeclinedForm(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return declSimpleNoun[case] else return declSimpleNoun[case] .. '<br>' .. altDeclSimpleNoun[case] end elseif alt == '2' then return altDeclSimpleNoun[case] else return declSimpleNoun[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. declSimpleNoun["defNomSg"] ..'\n|' .. declSimpleNoun["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("defConstrSg") ..'\n|' .. getDeclinedForm("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("defOblSg") ..'\n|' .. getDeclinedForm("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. getDeclinedForm("defDemonsOblSg") ..'\n|' .. getDeclinedForm("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. getDeclinedForm("vocSg") ..'\n|' .. getDeclinedForm("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. getDeclinedForm("indefNomSg") ..'\n|' .. getDeclinedForm("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("indefConstrSg") ..'\n|' .. getDeclinedForm("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("indefOblSg") ..'\n|' .. getDeclinedForm("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn, mk.: -- 1. {{#invoke:ku-tewîn-nav|tew|pos=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|pos=indefConstrSg}} -- Ji bo tabloyên formên navdêran: [[Şablon:ku-tewîn-navForm]] -- Bnr. [[sêva]], [[sêvê]], [[hevala]], [[hevalê]] -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export c86695ezn93f4oimpf9n2th8tol88xo 6291779 6291776 2026-07-28T02:12:56Z Ghybu 1393 link 6291779 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end -- Converts a semicolon-separated list of forms into a formatted string. -- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = link{term=mw.text.trim(v), lang=langKu} end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local declCompoundNoun = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. declCompoundNoun['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local declSimpleNoun = export.declSimpleNoun{noun, gender} local altDeclSimpleNoun = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if vocSg then declSimpleNoun["vocSg"] = formatForms(args['bang.yj']) altDeclSimpleNoun["vocSg"] = formatForms(args['bang.yj']) end if vocPl then declSimpleNoun["vocPl"] = formatForms(args['bang.pj']) altDeclSimpleNoun["vocPl"] = formatForms(args['bang.pj']) end if defOblSg then declSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) altDeclSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then declSimpleNoun["defOblSg"] = declSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} altDeclSimpleNoun["defOblSg"] = altDeclSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end local function getDeclinedForm(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return declSimpleNoun[case] else return declSimpleNoun[case] .. '<br>' .. altDeclSimpleNoun[case] end elseif alt == '2' then return altDeclSimpleNoun[case] else return declSimpleNoun[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. declSimpleNoun["defNomSg"] ..'\n|' .. declSimpleNoun["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("defConstrSg") ..'\n|' .. getDeclinedForm("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("defOblSg") ..'\n|' .. getDeclinedForm("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. getDeclinedForm("defDemonsOblSg") ..'\n|' .. getDeclinedForm("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. getDeclinedForm("vocSg") ..'\n|' .. getDeclinedForm("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. getDeclinedForm("indefNomSg") ..'\n|' .. getDeclinedForm("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("indefConstrSg") ..'\n|' .. getDeclinedForm("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("indefOblSg") ..'\n|' .. getDeclinedForm("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn: -- 1. {{#invoke:ku-tewîn-nav|tew|rewş=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|rewş=indefConstrSg}} -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export b7tgn7n9t5bo3etvxcm9n0w7df2p2zv 6291784 6291779 2026-07-28T02:23:11Z Ghybu 1393 + alt.bang.yj/alt.bang.pj 6291784 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end -- Converts a semicolon-separated list of forms into a formatted string. -- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = link{term=mw.text.trim(v), lang=langKu} end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local altVocSg = args['alt.bang.yj'] local altVocPl = args['alt.bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local declCompoundNoun = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. declCompoundNoun['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local declSimpleNoun = export.declSimpleNoun{noun, gender} local altDeclSimpleNoun = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if defOblSg then declSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) altDeclSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then declSimpleNoun["defOblSg"] = declSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} altDeclSimpleNoun["defOblSg"] = altDeclSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end if vocSg then declSimpleNoun["vocSg"] = formatForms(args['bang.yj']) altDeclSimpleNoun["vocSg"] = formatForms(args['bang.yj']) end if vocPl then declSimpleNoun["vocPl"] = formatForms(args['bang.pj']) altDeclSimpleNoun["vocPl"] = formatForms(args['bang.pj']) end if altVocSg then declSimpleNoun["vocSg"] = declSimpleNoun["alt.bang.yj"] .. ', ' .. link{term=args['alt.bang.yj'], lang=langKu} altDeclSimpleNoun["vocSg"] = declSimpleNoun["alt.bang.yj"] .. ', ' .. link{term=args['alt.bang.yj'], lang=langKu} end if altVocPl then declSimpleNoun["vocPl"] = declSimpleNoun["alt.bang.pl"] .. ', ' .. link{term=args['alt.bang.pl'], lang=langKu} altDeclSimpleNoun["vocPl"] = declSimpleNoun["alt.bang.pl"] .. ', ' .. link{term=args['alt.bang.pl'], lang=langKu} end local function getDeclinedForm(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return declSimpleNoun[case] else return declSimpleNoun[case] .. '<br>' .. altDeclSimpleNoun[case] end elseif alt == '2' then return altDeclSimpleNoun[case] else return declSimpleNoun[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. declSimpleNoun["defNomSg"] ..'\n|' .. declSimpleNoun["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("defConstrSg") ..'\n|' .. getDeclinedForm("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("defOblSg") ..'\n|' .. getDeclinedForm("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. getDeclinedForm("defDemonsOblSg") ..'\n|' .. getDeclinedForm("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. getDeclinedForm("vocSg") ..'\n|' .. getDeclinedForm("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. getDeclinedForm("indefNomSg") ..'\n|' .. getDeclinedForm("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("indefConstrSg") ..'\n|' .. getDeclinedForm("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("indefOblSg") ..'\n|' .. getDeclinedForm("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn: -- 1. {{#invoke:ku-tewîn-nav|tew|rewş=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|rewş=indefConstrSg}} -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export mxm8wbck32sp4fr21ln9hltgupys2zl 6291797 6291784 2026-07-28T02:31:35Z Ghybu 1393 6291797 Scribunto text/plain local export = {} -- ==== Ferheng: =============================================================== -- Declination (decl.) → Tewandin, tewîn -- Definite (def.) → Binavkirî, diyar -- Indefinite (indef.) → Nebinavkirî, nediyar -- Singular (Sg.) → Yekjimar -- Plural (Pl.) → Pirjimar -- Masculine (m.) → Nêr (n.) -- Feminine. (f.) → Mê (m.) -- Case → Rewş, awa -- Nominative (nom.) → Rewşa (awayê) navkî, netewandî, xwerû -- Construct (constr.) → Îzafe, ravek -- Oblique (obl.) → Rewşa (awayê) çemandî (tewandî) -- Demonstrative oblique (demons. obl.) → Rewşa nîşandera çem. -- Vocative (voc.) → Rewşa bangkirinê -- Alternative (alt.) → Guherto -- ============================================================================= local langKu = require("Modul:languages").getByCode("ku") local link = require('Module:links').language_link local gsub = mw.ustring.gsub local find = mw.ustring.find -- ============================================================================= -- NAVDÊRÊN HEVEDUDANÎ -- Di peyvên hevedudanî de (mk. [[hespê avê]] (nêr), [[odeya nivistinê]] (mê)) tenê -- peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere. -- Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa îzafeyî de ne. -- Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. -- ============================================================================= function export.declCompoundNoun(noun) local decl = {} local nounTab = mw.text.split(noun, '%s') local word1 = nounTab[1] local word2 = table.concat(nounTab, ' ', 2) decl.defSg = noun decl.defPl = gsub(word1, '(.)$', 'ên').. ' ' .. word2 -- The last letter of a singular compound noun determines its gender. -- If its ending is "-a", the compound noun is feminine; -- if it's ending is "-ê", it's masculine. if find(word1, 'a$') then decl.gender ='mê' decl.indefSg = gsub(word1, '(.)$', 'eke') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 elseif find(word1, 'ê$') then decl.gender ='nêr' decl.indefSg = gsub(word1, '(.)$', 'ekî') .. ' ' .. word2 decl.indefPl = gsub(word1, '(.)$', 'ine') .. ' ' .. word2 else return 'Zayenda peyva yekem nayê zanîn!' end return decl end -- ============================================================================= -- NAVDÊRÊN SADE -- ============================================================================= -- We need this function to create the demons. obl. case (nîşandera çem.)). -- ex. wê sêvê (f.) / wî gundî (m.) local function oblPronoun(gender) if gender == 'mê' then return 'wê' end if gender == 'nêr' then return 'wî' end end -- Function to make endings bold. local function b(bold) return '<b>' .. bold .. '</b>' end -- This function returns an array containing all possible declined forms of -- the simple noun for every grammatical case (definite/indefinite): -- nominative (navkî), construct (îzafe), oblique (çemandî). -- The demons. obl. (nîşandera çem.) and vocative (bangkirin) only exists -- in the definite form. function export.declSimpleNoun(opts) opts = opts or {} local noun = opts[1] local gender = opts[2] -- 'mê' or 'nêr' -- By default, display the standard form of the declension (1) -- '2' for the alternative form local alt = opts.alt or '1' -- By default, the tags are displayed(<br></br>, [[..]]).. -- tags='na' to disable it. local tags = opts.tags or 'erê' local decl = {} decl.defNomSg = noun decl.defNomPl = noun if (find(noun, '[bcçdfghjklmnpqrsştvwxyz]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('ê') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('î') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('ekî') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekî') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('o') decl.vocPl = noun .. b('ino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('a') decl.defConstrPl = noun .. b('ên') decl.defOblSg = noun .. b('ê') decl.defOblPl = noun .. b('an') decl.indefNomSg = noun .. b('ek') decl.indefNomPl = noun .. b('in') decl.indefConstrSg = noun .. b('eke') decl.indefConstrPl = noun .. b('ine') decl.indefOblSg = noun .. b('ekê') decl.indefOblPl = noun .. b('inan') decl.vocSg = noun .. b('ê') decl.vocPl = noun .. b('ino') end elseif (find(noun, '[ae]$') and alt == '2') then if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('ê')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('î')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kî')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('o')) decl.vocPl = gsub(noun, '(.)$', b('ino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('a')) decl.defConstrPl = gsub(noun, '(.)$', b('ên')) decl.defOblSg = gsub(noun, '(.)$', b('ê')) decl.defOblPl = gsub(noun, '(.)$', b('an')) decl.indefNomSg = gsub(noun, '(.)$', 'e' .. b('k')) decl.indefNomPl = gsub(noun, '(.)$', b('in')) decl.indefConstrSg = gsub(noun, '(.)$', 'e' .. b('ke')) decl.indefConstrPl = gsub(noun, '(.)$', b('ine')) decl.indefOblSg = gsub(noun, '(.)$', 'e' .. b('kê')) decl.indefOblPl = gsub(noun, '(.)$', b('inan')) decl.vocSg = gsub(noun, '(.)$', b('ê')) decl.vocPl = gsub(noun, '(.)$', b('ino')) end elseif (find(noun, '[aeiîouû]$')) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') if (find(noun, '[î]$')) then decl.defOblSg = noun else decl.defOblSg = noun .. b('yî') end decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yê') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end elseif (find(noun, '[ê]$')) then if (alt == 2) then if (gender == 'nêr') then decl.defConstrSg = noun .. b('yê') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun .. b('yî') decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yekî') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekî') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yo') decl.vocPl = noun .. b('yino') elseif (gender == 'mê') then decl.defConstrSg = noun .. b('ya') decl.defConstrPl = noun .. b('yên') decl.defOblSg = noun decl.defOblPl = noun .. b('yan') decl.indefNomSg = noun .. b('yek') decl.indefNomPl = noun .. b('yin') decl.indefConstrSg = noun .. b('yeke') decl.indefConstrPl = noun .. b('yine') decl.indefOblSg = noun .. b('yekê') decl.indefOblPl = noun .. b('yinan') decl.vocSg = noun .. b('yê') decl.vocPl = noun .. b('yino') end else if (gender == 'nêr') then decl.defConstrSg = gsub(noun, '(.)$', b('iyê')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = gsub(noun, '(.)$', b('iyî')) decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyekî')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekî')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyo')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) elseif (gender == 'mê') then decl.defConstrSg = gsub(noun, '(.)$', b('iya')) decl.defConstrPl = gsub(noun, '(.)$', b('iyên')) decl.defOblSg = noun decl.defOblPl = gsub(noun, '(.)$', b('iyan')) decl.indefNomSg = gsub(noun, '(.)$', b('iyek')) decl.indefNomPl = gsub(noun, '(.)$', b('iyin')) decl.indefConstrSg = gsub(noun, '(.)$', b('iyeke')) decl.indefConstrPl = gsub(noun, '(.)$', b('iyine')) decl.indefOblSg = gsub(noun, '(.)$', b('iyekê')) decl.indefOblPl = gsub(noun, '(.)$', b('iyinan')) decl.vocSg = gsub(noun, '(.)$', b('iyê')) decl.vocPl = gsub(noun, '(.)$', b('iyino')) end end end -- Spelling correction (îy → iy) + link for i, v in pairs(decl) do if (tags == 'na') then decl[i] = mw.ustring.gsub(decl[i], '<b>(.+)</b>', '%1') decl[i] = gsub(decl[i], 'îy', 'iy') else decl[i] = gsub(decl[i], 'î<b>y', '<b>iy') decl[i] = link{term=decl[i], lang=langKu} end end -- Zêdekirina cînavên wê/wî/wan ji bo nîşandera çemandî. decl.defDemonsOblSg = oblPronoun(gender) .. ' ' .. decl.defOblSg decl.defDemonsOblPl = 'wan ' .. decl.defOblPl return decl end -- ============================================================================= -- DAWÎ -- ============================================================================= -- ───────────────────────────────────────────────────────────────────────────── -- ÇÊKIRINA TABLOYA GOTARÊ: [[Şablon:ku-tewîn-nav]] -- Bnr. [[sêv]], [[gund]], [[bajar]], [[rê]] -- ───────────────────────────────────────────────────────────────────────────── local function formatGenderHeader(gender) if (gender == 'nêr') then return ' Zayenda nêr a' elseif (gender == 'mê') then return ' Zayenda mê ya' end end -- Converts a semicolon-separated list of forms into a formatted string. -- Trims whitespace and uses ', ' as default separator. local function formatForms(forms, sep) if not forms or forms == "" then return "" end sep = sep or ', ' local formTable = mw.text.split(forms, ';') for i, v in ipairs(formTable) do formTable[i] = link{term=mw.text.trim(v), lang=langKu} end return table.concat(formTable, sep) end function export.tewandin(frame) local args = frame:getParent().args local noun = args[1] local gender = args[2] local singular = args[3] local alt = args['guherto'] -- Parametre ji bo formên ne standard local vocSg = args['bang.yj'] local vocPl = args['bang.pj'] local altVocSg = args['alt.bang.yj'] local altVocPl = args['alt.bang.pj'] local defOblSg = args['çem.yj'] local altDefOblSg = args['alt.çem.yj'] local declMNtab = require('Modul:ku-tewîn-nav/mê û nêr').declMNtable local declSingularTab = require('Modul:ku-tewîn-nav/yekjimar').declSingularTable if (gender == 'mê û nêr') then return declMNtab(noun, alt) elseif (singular == 'y') then return declSingularTab(noun, gender, alt) elseif gender == '-' then local declCompoundNoun = export.declCompoundNoun(noun, gender) return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" | Tewandin: zayenda ' .. declCompoundNoun['gender'] .. ' &nbsp;&nbsp;' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez"| Binavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["defPl"]} ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nebinavkirî' ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefSg"]} ..'\n|' .. link{lang=langKu, term=declCompoundNoun["indefPl"]} ..'\n|-' ..'\n| colspan="3" align="center" style="font-size:x-small;" | <b style="color:green">Agahdarî</b>: Di peyvên <u>hevedudanî</u> de tenê peyva<br>yekem li gor diyarîtiyê û li gor hejmarê diguhere.' ..'\n|}' else local declSimpleNoun = export.declSimpleNoun{noun, gender} local altDeclSimpleNoun = export.declSimpleNoun{noun, gender, alt='2'} -- Formên "Nîşandera çemandî" li gorî formên çemandî yên standard tên çêkirin: -- Bo mînak "wî bajarî" rast e feqet "wî bajêr" nayê bikaranîn -- Binêre gotûbêja [[Wîkîferheng:Dîwan/2023#dayê/diyê]] if defOblSg then declSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) altDeclSimpleNoun["defOblSg"] = formatForms(args['çem.yj']) elseif altDefOblSg then declSimpleNoun["defOblSg"] = declSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} altDeclSimpleNoun["defOblSg"] = altDeclSimpleNoun["defOblSg"] .. ', ' .. link{term=args['alt.çem.yj'], lang=langKu} end if vocSg then declSimpleNoun["vocSg"] = formatForms(args['bang.yj']) altDeclSimpleNoun["vocSg"] = formatForms(args['bang.yj']) elseif altVocSg then declSimpleNoun["vocSg"] = declSimpleNoun["vocSg"] .. ', ' .. link{term=args['alt.bang.yj'], lang=langKu} altDeclSimpleNoun["vocSg"] = declSimpleNoun["vocSg"] .. ', ' .. link{term=args['alt.bang.yj'], lang=langKu} end if vocPl then declSimpleNoun["vocPl"] = formatForms(args['bang.pj']) altDeclSimpleNoun["vocPl"] = formatForms(args['bang.pj']) elseif altVocPl then declSimpleNoun["vocPl"] = declSimpleNoun["vocPl"] .. ', ' .. link{term=args['alt.bang.pl'], lang=langKu} altDeclSimpleNoun["vocPl"] = declSimpleNoun["vocPl"] .. ', ' .. link{term=args['alt.bang.pl'], lang=langKu} end local function getDeclinedForm(case) if alt == 'hemû' then if (vocSg ~= nil or vocPl ~= nil or defOblSg ~= nil) then return declSimpleNoun[case] else return declSimpleNoun[case] .. '<br>' .. altDeclSimpleNoun[case] end elseif alt == '2' then return altDeclSimpleNoun[case] else return declSimpleNoun[case] end end return '{| class="wikitable tablo-flip tewandin-tablo mw-collapsible"' ..'\n|-' ..'\n! colspan="3" class="row-flip tewandin-header"| Tewandina <i>' .. noun .. '</i>&nbsp;&nbsp;' ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' binavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. declSimpleNoun["defNomSg"] ..'\n|' .. declSimpleNoun["defNomPl"] ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("defConstrSg") ..'\n|' .. getDeclinedForm("defConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("defOblSg") ..'\n|' .. getDeclinedForm("defOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Nîşandera çem.' ..'\n|' .. getDeclinedForm("defDemonsOblSg") ..'\n|' .. getDeclinedForm("defDemonsOblPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Bangkirin' ..'\n|' .. getDeclinedForm("vocSg") ..'\n|' .. getDeclinedForm("vocPl") ..'\n|-' ..'\n! colspan="3" class="tewandin-header2" align="center" |' .. formatGenderHeader(gender) .. ' nebinavkirî' ..'\n|-' ..'\n! class="row-flip tewandin-header3" | Rewş' ..'\n! class="tewandin-header3" | Yekjimar' ..'\n! class="tewandin-header3" | Pirjimar' ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Navkî' ..'\n|' .. getDeclinedForm("indefNomSg") ..'\n|' .. getDeclinedForm("indefNomPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Îzafe' ..'\n|' .. getDeclinedForm("indefConstrSg") ..'\n|' .. getDeclinedForm("indefConstrPl") ..'\n|-' ..'\n! class="row-flip tewandin-rez" | Çemandî' ..'\n|' .. getDeclinedForm("indefOblSg") ..'\n|' .. getDeclinedForm("indefOblPl") ..'\n|}' end end -- ───────────────────────────────────────────────────────────────────────────── -- Bikaranîn: -- 1. {{#invoke:ku-tewîn-nav|tew|rewş=indefOblSg}} -- 2. {{#invoke:ku-tewîn-nav|tew|nêr|rewş=indefConstrSg}} -- ───────────────────────────────────────────────────────────────────────────── function export.tew(frame) local args = frame:getParent().args local noun = args[1] local gender = frame.args[1] or args[2] local alt = args['guherto'] local case = frame.args['rewş'] if alt == 'hemû' then local tew_hemu = export.declSimpleNoun{noun, gender, alt='1'}[case] .. '<br>' .. export.declSimpleNoun{noun, gender, alt='2'}[case] return tew_hemu else return export.declSimpleNoun{noun, gender, alt=alt}[case] end end -- ───────────────────────────────────────────────────────────────────────────── -- Get comma separated forms -- Bnr. [[MediaWiki:Gadget-QQ.js]] -- ───────────────────────────────────────────────────────────────────────────── function export.get_comma_separated_forms(frame) local noun = frame.args[1] local gender = frame.args[2] local declResults local declResults2 local forms = {} if gender == "mê û nêr" then declResults = export.declSimpleNoun{noun, 'nêr', tags='na'} declResults2 = export.declSimpleNoun{noun, 'mê', alt="2", tags='na'} for k, v in pairs(declResults2) do table.insert(forms, v) end else declResults = export.declSimpleNoun{noun, gender, tags='na'} end for k, v in pairs(declResults) do table.insert(forms, v) end -- Remove duplicate elements local newForms = {} local checkForms = {} for _, v in ipairs(forms) do if not checkForms[v] then checkForms[v] = true table.insert(newForms, v) end end return table.concat(newForms, ',') end return export 49wce9jlo4dkeiigy8fwzvj4l6n0kbq Şablon:ku-tewîn-nav 10 652550 6291697 6236919 2026-07-27T20:15:35Z Ghybu 1393 + kat 6291697 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/> <includeonly>{{#invoke:ku-tewîn-nav|tewandin}}<!-- <!-- ======================================= KATEGORÎ ======================================= -->{{#if:{{{guherto|}}}|[[Kategorî:Navdêrên kurdî bi formên alternatîv]]}}<!-- -->{{#if:{{{çemandî_y|}}}{{bang_y}}}|[[Kategorî:Navdêrên kurdî bi formên nestandard]]}}</includeonly><noinclude> {{belgekirin}} </noinclude> mvjuxt45wa99n8gvnxi7bwcd21ys329 6291698 6291697 2026-07-27T20:19:36Z Ghybu 1393 6291698 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/> <includeonly>{{#invoke:ku-tewîn-nav|tewandin}}<!-- <!-- ======================================= KATEGORÎ ======================================= -->{{#if:{{{guherto|}}}|[[Kategorî:Navdêrên kurdî bi formên alternatîv]]}}<!-- -->{{#if:{{{çemandî_y|}}}{{{bang_y|}}}|[[Kategorî:Navdêrên kurdî bi formên nestandard]]}}</includeonly><noinclude> {{belgekirin}} </noinclude> 93io4n039zymvsqk34xma79x72xzbge 6291705 6291698 2026-07-27T20:30:46Z Ghybu 1393 kurmancî 6291705 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/> <includeonly>{{#invoke:ku-tewîn-nav|tewandin}}<!-- <!-- ======================================= KATEGORÎ ======================================= -->{{#if:{{{guherto|}}}|[[Kategorî:Navdêrên kurmancî bi formên alternatîv]]}}<!-- -->{{#if:{{{çemandî_y|}}}{{{bang_y|}}}|[[Kategorî:Navdêrên kurmancî bi formên nestandard]]}}</includeonly><noinclude> {{belgekirin}} </noinclude> f5kfbauorc3umco276dyiaog5lwoif3 6291756 6291705 2026-07-27T23:20:09Z Ghybu 1393 6291756 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/> <includeonly>{{#invoke:ku-tewîn-nav|tewandin}}<!-- <!-- ======================================= KATEGORÎ ======================================= -->{{#if:{{{guherto|}}}|[[Kategorî:Navdêrên kurmancî bi formên alternatîv]]}}<!-- -->{{#if:{{{alt.çem.yj|}}}{{{çem.yj|}}}{{{bang.yj|}}}{{{bang.pj|}}}|[[Kategorî:Navdêrên kurmancî bi formên nestandard]]}}</includeonly><noinclude> {{belgekirin}} </noinclude> qzu2m8jdqzek9esc3h84fmouf8q99qs 6291802 6291756 2026-07-28T02:39:58Z Ghybu 1393 kat. 6291802 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/> <includeonly>{{#invoke:ku-tewîn-nav|tewandin}}<!-- <!-- ======================================= KATEGORÎ ======================================= -->{{#if:{{{guherto|}}}|[[Kategorî:Navdêrên kurmancî bi formên alternatîv]]}}<!-- -->{{#if:{{{alt.çem.yj|}}}{{{çem.yj|}}}{{{bang.yj|}}}{{{bang.pj|}}}{{{alt.bang.yj|}}}{{{alt.bang.pj|}}}|[[Kategorî:Navdêrên kurmancî bi formên nestandard]]}}</includeonly><noinclude> {{belgekirin}} </noinclude> 7krgm14fuybf2j5wotts2xq3ezkopj1 Şablon:ku-tewîn-nav/belge 10 652624 6291765 6236930 2026-07-27T23:37:23Z Ghybu 1393 /* Bikaranîn */ 6291765 wikitext text/x-wiki {{Lua bikartîne|Modul:ku-tewîn-nav}} {{TemplateStyles|Şablon:ku-tewîn/style.css}} {{agahdarî}} {{bilezkirî}} == Bikaranîn == <syntaxhighlight lang="wikitext"> {{ku-tewîn-nav|peyv|zayend}} {{ku-tewîn-nav|peyv|zayend|<jimar>|guherto=}} </syntaxhighlight> ;Ji bo peyvên hevedudanî <syntaxhighlight lang="wikitext"> {{ku-tewîn-nav|peyva hevedudanî|-}} </syntaxhighlight> <blockquote style="background-color:#FFFFE0; border-left-color:orange; font-size:small; padding:5px 5px;"> Di peyvên {{g|ku|hevedudanî}} de tenê peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere.<br> Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa [[îzafe|îzafeyî]] de ne.<br> Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. </blockquote> === Parametre === * {{param2|1}} peyv * {{param2|2}} zayend: {{kod|mê}} / {{kod|nêr}} / {{kod|mê û nêr}} / {{kod|-}} * {{param2|3}} jimar: {{kod|y}} tenê kolona yekjimar derdikevî * {{param2|guherto|2}} ji bo guhertoya nestandardê<br> {{param2|guherto|hemû}} herdû form: standard + nestandard <u>Ji bo formên ne standard</u> (bi gelemperî rewşa çemandî ya {{g|ku|nêr}} a yekjimar, wekî {{q|ku|bajar}}, {{q|ku|nan}}, {{q|ku|hesp}}, {{q|ku|aş}}, ...): * {{param2|çem.yj}} Dikeve şûna forma standard: ''Forma çemandî ya yekjimar a binavkirî'' * {{param2|alt.çem.yj}} Formê lê zêde dike (forma standard + forma alternatîv): ''Forma alternatîv a çemandî ya yekjimar a binavkirî'' *: {{q|ku|bajar}} → <syntaxhighlight lang="wikitext" inline>{{ku-tewîn-nav|bajar|nêr|alt.çem.yj=bajêr}}</syntaxhighlight> *: {{q|ku|aş}} → <syntaxhighlight lang="wikitext" inline>{{ku-tewîn-nav|aş|nêr|alt.çem.yj=êş}}</syntaxhighlight> * {{param2|bang.yj}}, {{param2|bang.pj}} Formên bangkirinê yên yekjimar û pirjimar ên binavkirî *: {{q|ku|dê}} → <syntaxhighlight lang="wikitext" inline>{{ku-tewîn-nav|dê|mê|bang.yj=dayê|bang.pj=dayikino}}</syntaxhighlight> == Mînak == ;Navdêr {| |<center><code><nowiki>{{ku-tewîn-nav|sêv|mê}}</nowiki></code></center><br/>{{ku-tewîn-nav|sêv|mê}} |<center><code><nowiki>{{ku-tewîn-nav|gund|nêr}}</nowiki></code></center><br/>{{ku-tewîn-nav|gund|nêr}} |<center><code><nowiki>{{ku-tewîn-nav|heval|mê û nêr}}</nowiki></code></center><br/>{{ku-tewîn-nav|heval|mê û nêr}} |} ;Navdêrên hevedudanî {| |<center><code><nowiki>{{ku-tewîn-nav|odeya nivistinê|-}}</nowiki></code></center><br/>{{ku-tewîn-nav|odeya nivistinê|-}} |<center><code><nowiki>{{ku-tewîn-nav|hespê avê|-}}</nowiki></code></center><br/>{{ku-tewîn-nav|hespê avê|-}} |} ;Serenav {| |<center><code><nowiki>{{ku-tewîn-nav|Makedonya|mê|y}}</nowiki></code></center><br/>{{ku-tewîn-nav|Makedonya|mê|y}} |} == Binêre == * {{şl|ku-tewîn-navForm}} * {{şl|ku-tewîn-rd}} * {{şl|ku-tewîn-lk}} * {{şl|ku-tewandin}} == Daneyên şablonê == <templatedata> { "params": { "1": { "label": "peyv", "type": "string", "required": true, "description": "peyv" }, "2": { "label": "zayend", "description": " \"mê\" an \"nêr\" an jî \"mê û nêr\" an \"-\" ji bo ku zayend dernekeve", "example": "mê û nêr", "required": true, "type": "string" }, "3": { "label": "jimar", "description": "Ji bo ku tenê kolona yekjimar derkeve \"y\" bi kar bîne ", "example": "y", "type": "string" }, "guherto": { "label": "guherto", "description": "Ji bo peyvên bi -e diqedin, guherto=2 bi kar bînin", "example": "2", "type": "number" } }, "description": "Şablona tewandinên navdêrên kurmancî", "paramOrder": [ "1", "2", "3", "guherto" ] } </templatedata> <includeonly> [[Kategorî:Şablonên navdêrên {{navê zimanî|ku}}]] </includeonly> sj8ow0blgli4mekb7bwn3bq9e5p89ae 6291799 6291765 2026-07-28T02:35:39Z Ghybu 1393 + parametre 6291799 wikitext text/x-wiki {{Lua bikartîne|Modul:ku-tewîn-nav}} {{TemplateStyles|Şablon:ku-tewîn/style.css}} {{agahdarî}} {{bilezkirî}} == Bikaranîn == <syntaxhighlight lang="wikitext"> {{ku-tewîn-nav|peyv|zayend}} {{ku-tewîn-nav|peyv|zayend|<jimar>|guherto=}} </syntaxhighlight> ;Ji bo peyvên hevedudanî <syntaxhighlight lang="wikitext"> {{ku-tewîn-nav|peyva hevedudanî|-}} </syntaxhighlight> <blockquote style="background-color:#FFFFE0; border-left-color:orange; font-size:small; padding:5px 5px;"> Di peyvên {{g|ku|hevedudanî}} de tenê peyva yekem li gor diyarîtiyê (binavkirî/nebinavkirî) û li gor hejmarê diguhere.<br> Ew li gor rewşê (navkî, çemandî, îzafe) naguherin: herdem di rewşa [[îzafe|îzafeyî]] de ne.<br> Zayenda peyva hevedudanî, zayenda peyva yekem e ji ber ku li gor wê tê tewandin. </blockquote> === Parametre === * {{param2|1}} peyv * {{param2|2}} zayend: {{kod|mê}} / {{kod|nêr}} / {{kod|mê û nêr}} / {{kod|-}} * {{param2|3}} jimar: {{kod|y}} tenê kolona yekjimar derdikevî * {{param2|guherto|2}} ji bo guhertoya nestandardê<br> {{param2|guherto|hemû}} herdû form: standard + nestandard <u>Ji bo formên ne standard</u> (bi gelemperî rewşa çemandî ya {{g|ku|nêr}} a yekjimar, wekî {{q|ku|bajar}}, {{q|ku|nan}}, {{q|ku|hesp}}, {{q|ku|aş}}, ...): * {{param2|çem.yj}} Dikeve şûna forma standard: ''Forma çemandî ya yekjimar a binavkirî'' * {{param2|alt.çem.yj}} Formê lê zêde dike (forma standard + forma alternatîv): ''Forma alternatîv a çemandî ya yekjimar a binavkirî'' *: {{q|ku|bajar}} → <syntaxhighlight lang="wikitext" inline>{{ku-tewîn-nav|bajar|nêr|alt.çem.yj=bajêr}}</syntaxhighlight> *: {{q|ku|aş}} → <syntaxhighlight lang="wikitext" inline>{{ku-tewîn-nav|aş|nêr|alt.çem.yj=êş}}</syntaxhighlight> * {{param2|bang.yj}}, {{param2|bang.pj}} Formên bangkirinê yên yekjimar û pirjimar ên binavkirî * {{param2|alt.bang.yj}}, {{param2|alt.bang.pj}} Ji bo formên alternatîv (formê lê zêde dike) *: {{q|ku|dê}} → <syntaxhighlight lang="wikitext" inline>{{ku-tewîn-nav|dê|mê|bang.yj=dayê|bang.pj=dayikino}}</syntaxhighlight> == Mînak == ;Navdêr {| |<center><code><nowiki>{{ku-tewîn-nav|sêv|mê}}</nowiki></code></center><br/>{{ku-tewîn-nav|sêv|mê}} |<center><code><nowiki>{{ku-tewîn-nav|gund|nêr}}</nowiki></code></center><br/>{{ku-tewîn-nav|gund|nêr}} |<center><code><nowiki>{{ku-tewîn-nav|heval|mê û nêr}}</nowiki></code></center><br/>{{ku-tewîn-nav|heval|mê û nêr}} |} ;Navdêrên hevedudanî {| |<center><code><nowiki>{{ku-tewîn-nav|odeya nivistinê|-}}</nowiki></code></center><br/>{{ku-tewîn-nav|odeya nivistinê|-}} |<center><code><nowiki>{{ku-tewîn-nav|hespê avê|-}}</nowiki></code></center><br/>{{ku-tewîn-nav|hespê avê|-}} |} ;Serenav {| |<center><code><nowiki>{{ku-tewîn-nav|Makedonya|mê|y}}</nowiki></code></center><br/>{{ku-tewîn-nav|Makedonya|mê|y}} |} == Binêre == * {{şl|ku-tewîn-navForm}} * {{şl|ku-tewîn-rd}} * {{şl|ku-tewîn-lk}} * {{şl|ku-tewandin}} == Daneyên şablonê == <templatedata> { "params": { "1": { "label": "peyv", "type": "string", "required": true, "description": "peyv" }, "2": { "label": "zayend", "description": " \"mê\" an \"nêr\" an jî \"mê û nêr\" an \"-\" ji bo ku zayend dernekeve", "example": "mê û nêr", "required": true, "type": "string" }, "3": { "label": "jimar", "description": "Ji bo ku tenê kolona yekjimar derkeve \"y\" bi kar bîne ", "example": "y", "type": "string" }, "guherto": { "label": "guherto", "description": "Ji bo peyvên bi -e diqedin, guherto=2 bi kar bînin", "example": "2", "type": "number" } }, "description": "Şablona tewandinên navdêrên kurmancî", "paramOrder": [ "1", "2", "3", "guherto" ] } </templatedata> <includeonly> [[Kategorî:Şablonên navdêrên {{navê zimanî|ku}}]] </includeonly> fuaty3edg6x3j1knqokbjizp28jlnm9 Şablon:ku-tewîn-rd 10 687994 6291809 6236923 2026-07-28T04:00:17Z Calak 1064 navendî 6291809 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/><includeonly> {| class="wikitable tablo-flip tewandin-tablo" style="text-align:center;" |- ! Pozîtîv ! Komparatîv ! Sûperlatîv |- | {{g-|{{{1}}}}} | {{preload2|girêdan={{{1}}}tir|nivîs={{{1}}}'''tir'''|preload=Şablon:komparatîv/mînak|kod={{{1}}}}} |'''herî'''&nbsp;{{{1}}}&nbsp;<i>([[kurmanciya navendî|navendî]])</i><br><!-- -->'''tewrî'''&nbsp;{{{1}}}&nbsp;<i>([[kurmanciya rojavayî|rojavayî]])</i><br><!-- -->{{#if:{{{tirîn|}}}|{{preload2|girêdan={{{1}}}tirîn|nivîs={{{1}}}'''tirîn'''|preload=Şablon:sûperlatîv/mînak|kod={{{1}}}}}&nbsp;<i>({{w|Soranîzm (ziman)|soranîzm}})</i>|{{#ifexist:{{{1}}}tirîn|{{preload2|girêdan={{{1}}}tirîn|nivîs={{{1}}}'''tirîn'''|preload=Şablon:sûperlatîv/mînak|kod={{{1}}}}}&nbsp;<i>({{w|Soranîzm (ziman)|soranîzm}})</i>}}}} |}</includeonly><noinclude>{{belgekirin}}</noinclude> 7iih86s0k60kw925bo603cofe116m1z 6291810 6291809 2026-07-28T05:19:08Z Wikihez 7344 Reverted 1 edit by [[Special:Contributions/Calak|Calak]] ([[User talk:Calak|talk]]): Jkx li gotûbêjê binivîse ev guhartin çawa wîkîferhengê baştir û fambartir dike ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291810 wikitext text/x-wiki <templatestyles src="Şablon:ku-tewîn/style.css"/><includeonly> {| class="wikitable tablo-flip tewandin-tablo" style="text-align:center;" |- ! Pozîtîv ! Komparatîv ! Sûperlatîv |- | {{g-|{{{1}}}}} | {{preload2|girêdan={{{1}}}tir|nivîs={{{1}}}'''tir'''|preload=Şablon:komparatîv/mînak|kod={{{1}}}}} |'''herî'''&nbsp;{{{1}}}&nbsp;<i>([[kurmanciya navendî|merkezî]])</i><br><!-- -->'''tewrî'''&nbsp;{{{1}}}&nbsp;<i>([[kurmanciya rojavayî|rojavayî]])</i><br><!-- -->{{#if:{{{tirîn|}}}|{{preload2|girêdan={{{1}}}tirîn|nivîs={{{1}}}'''tirîn'''|preload=Şablon:sûperlatîv/mînak|kod={{{1}}}}}&nbsp;<i>({{w|Soranîzm (ziman)|soranîzm}})</i>|{{#ifexist:{{{1}}}tirîn|{{preload2|girêdan={{{1}}}tirîn|nivîs={{{1}}}'''tirîn'''|preload=Şablon:sûperlatîv/mînak|kod={{{1}}}}}&nbsp;<i>({{w|Soranîzm (ziman)|soranîzm}})</i>}}}} |}</includeonly><noinclude>{{belgekirin}}</noinclude> ew5acc9gl7vc515h01dnos15u18ix4f xeyirandinê 0 734206 6291795 4343087 2026-07-28T02:29:45Z Wikihez 7344 /* Formeke navdêrê */ 6291795 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{ku-tew-nav|xeyirandin|mê}} {{navdêr|ku|form=erê}} # {{ku-tewîna-nav|xeyirandin|mê}} aufmqm9dxb77f5fcirfadawvk2i1lz9 xeyirandinan 0 748422 6291796 4343080 2026-07-28T02:30:41Z Wikihez 7344 /* Formeke navdêrê */ 6291796 wikitext text/x-wiki == {{ziman|ku}} == === Formeke navdêrê === {{ku-tew-nav|xeyirandin|mê}} {{navdêr|ku|form=erê}} # {{ku-tewîna-nav|xeyirandin|mê}} aufmqm9dxb77f5fcirfadawvk2i1lz9 Wîkîferheng:Daxwazên peyitandinê 4 843283 6291761 6290845 2026-07-27T23:34:40Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina 2 madeyan li [[Gotûbêj:bêonurane]], [[Gotûbêj:sabûnsazxane]] 6291761 wikitext text/x-wiki {{/destpêk}} = Hezîran 2020 = == [[romî#Navdêr|romî]] == Li Şingalê maneya polîs? --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 08:00, 15 hezîran 2020 (UTC) = Tîrmeh 2020 = == [[kêlb#p-mane|kêlb]] == --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:24, 22 tîrmeh 2020 (UTC) == [[ejî#p-mane|ejî]] == --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:24, 22 tîrmeh 2020 (UTC) == [[tutirk#peyitandin|tutirk]] == --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:02, 22 tîrmeh 2020 (UTC) :{{r|Guherto}} Niha çawa ye? Bi ya min çavkaniyên ku min dane têrê me dike. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:43, 22 tîrmeh 2020 (UTC) ::{{r|Balyozxane}} Nizanim.. li hin deveran wek tutirk hatîye nivîsandin û li hin jî wek tûtirk. Li hin deveran bi wateya tûşêmî (Rubus) ye, hin deveran jî bi wateya tûerd (Fragaria × ananassa) e û carna jî bi wateya tû (ê spî û reş go li ser daran çê dibin) ye. -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 08:16, 23 tîrmeh 2020 (UTC) == [[erbane#p-mane|erbane]] == Ji bo ''Amûreke tenê tekerekî wê heye ji bo veguhestina tiştan wek: axê, kevir, hwd'' ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]''--[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:42, 31 tîrmeh 2020 (UTC) = Tebax 2020 = == [[cifta berazan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:57, 9 tebax 2020 (UTC) == [[tê gerîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:26, 10 tebax 2020 (UTC) == [[tapor]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:30, 22 tebax 2020 (UTC) :{{r|Mihemed Qers}} -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 22:16, 22 tebax 2020 (UTC) == [[şimzare]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:01, 26 tebax 2020 (UTC) == [[bîrkok]] == Tenê Mehmed Uzun bi kar tîne. Ji bilî kitêbên wî çavkaniyeke din tune. —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:38, 28 tebax 2020 (UTC) == [[hunera axaftinê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:46, 30 tebax 2020 (UTC) == [[derrijîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 07:38, 31 tebax 2020 (UTC) == [[yekal]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 09:19, 31 tebax 2020 (UTC) == [[av û agir]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:50, 31 tebax 2020 (UTC) : Di çavkaniyeke de wek av û agir kirin derbas dibe û ji wergerandinên inglîzî cuda ye lê nêzîk e.<br> {{jêder-pirtûk|ku|jêgirtin=weke gelek hunermendên ko dû re agir bera berhêm xwe didin Xwedê jî ji bilî maltaba Nûh tevayiyê vê berhema xwe '''av û agir dike''', van melekên xwe yên doxînsist dikişîne asîmanan, li wir wan tawanbar dike, mîna ko bibêje: de biçin û weke xwe bikin, bi derew û tevgerên xwe yên qirêj dijminiya min bikin, Xwedê wan ji asimanan de serjêr davêje xwarê.|nivîskar=Hesenê Metê|sernav=Labîrenta cinan|weşanxane=Nefel|sal=2002|rûpel=132}} --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:37, 31 tebax 2020 (UTC) == [[elm#p-mane-notice|elm]] == Wateya: ''[[ewlebûn]], sihê pê zanîn, baş pê zanîn''. ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:31, 31 tebax 2020 (UTC) :{{r|Hakîmo}} Ku çavkanî tunebûn em ê jê bibin. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:47, 19 îlon 2020 (UTC) ::{{r|Balyozxane}} Mala te neketê... Hingê bixwe here lê bigere. Jixwe ez reşwî me. Ma eve ne çavkanî ye? -- [[Bikarhêner:Hakîmo|Hakîmo]] ([[Gotûbêja bikarhêner:Hakîmo|gotûbêj]]) 14:48, 19 îlon 2020 (UTC) :::{{r|Hakîmo}} Hinek bixwîne [[Wîkîferheng:Pîvekên tevlîkirinê]]. Jixwe dema ti kesan din çavkanî lê zêde nakin, ez lê digerim û zêde dikim. Na tu ne ti çavkanî yî. Çavkaniyên nivîskî hewce ne. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:51, 19 îlon 2020 (UTC) ::::{{r|Balyozxane}} Erê, lê ku tine bin em çawa bikinî? Em hema jê bibinî? -- [[Bikarhêner:Hakîmo|Hakîmo]] ([[Gotûbêja bikarhêner:Hakîmo|gotûbêj]]) 14:52, 19 îlon 2020 (UTC) :::::{{r|Hakîmo}} Erê em jê dibin. Lê peyvên jê hatine birin em li rûpela [[Pêvek:Bêçavkanî]] zêde dikin. bnr. [[:Kategorî:Pêvek bêçavkanî]]. Dîsa jî ez jî ji vê rewşa me aciz im û bi ya min peyvên devokî divê nayên jêbirin. Lê ji ber ku [[Wîkîferheng:Rêbazname]] dibêje divê werin jêbirin, ez jê dibim. Hevalên {{r|Jiju|Guherto|Ghybu}} [https://ku.wiktionary.org/wiki/Got%C3%BBb%C3%AAj:kejm%C3%BBn], [https://ku.wiktionary.org/wiki/Got%C3%BBb%C3%AAja_p%C3%AAvek%C3%AA:B%C3%AA%C3%A7avkan%C3%AE] jî ji vê rewşê aciz in. Lê ti kes gotûbêj nadin destpêkirin. Ku tu li vir [[Gotûbêja Wîkîferhengê:Pîvekên tevlîkirinê]] gotûbêjek bidî destpêkirin, ez ê piştgirî bidime te. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:58, 19 îlon 2020 (UTC) ::::::Ji kerema xwe min şaş fêm mekin feqet hemû bikarhêner ku tên vira dilpak nînin. Em çito ew peyvan kotrol bikinê? Mixabin, ji bo konrolkirina peyvan di destên me de tenê xwastina çavkaniyan hene amûrek din tine ye... PS: Herwiha me li ser wîkîferhengê Namespace'yên Nimînok ([[Nimînok:Kurdî/serhedî]]?, [[Nimînok:Kurdî/badînî]]?, ..) û Portal ([[Portal:Kurdî]], [[Portal:Frensî]] (mk. [[:fr:Portail:Français]]), ...) jî çêkiriye...--[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:32, 19 îlon 2020 (UTC) :::::::Nizanim we nivîsa vira xwand, [[Wîkîferheng:Dîwan#Skotî]]. Piraniya peyvên wîkiya skotî çêkirî ne...--[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:47, 19 îlon 2020 (UTC) ::::::::@Ghybu erê min ew xwendibû. Ku em peyvan nepeyitînin, rewşa me jî wek mg.wikt û wikiya skotiyan be. Temam em peyvên devokî jê nebin lê em wan jî nexin werger û rûpelên din heta ku werin peyitandin. Herwiha tu dibêjî amûrek tune ye lê tenê ji bo peyvên devokî û navên heywan/riwekan wisa ye. Gelek caran peyitandin pir hêsan e. Mînak @Hakîmo yan jî hevalên din dikarin blogan binivîsin daku em karibin peyvên wan yên devokî (nepeyitandî) têxin rûpela [[Wîkîferheng:Tomarkirina peyvên ji wêjeya kurdî|Jêgirtinekê tomar bike]] û kengî ew peyv ji hêla nivîskar û blogvanên kurd yên din ve hatine bikaranîn hingê em dikarin li wîkîferhengê jî zêde bikin. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:05, 19 îlon 2020 (UTC) {{outdent|::::::::}}{{r|Hakîmo|Ghybu}} Xêra dê û bavên we '''[[Gotûbêja_Wîkîferhengê:Pîvekên_tevlîkirinê#Li_ser_peyvên_devokî|li vir]]''' fikrên xwe binivîsin daku kesên din bizanin kesên din jî hene vê fikrê min dipejirînin. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 06:48, 3 çiriya pêşîn 2020 (UTC) == [[nîşanbar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 23:51, 31 tebax 2020 (UTC) = Îlon 2020 = == [[besme]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 11:26, 1 îlon 2020 (UTC) == [[ferengi]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:12, 1 îlon 2020 (UTC) == [[çelape]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:22, 1 îlon 2020 (UTC) == [[cesasandin]] == Çavkaniyek klasîk heye, yên din heye gelo? —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 09:02, 2 îlon 2020 (UTC) == [[depan]] == Depan guhertoyeke textan an textîn e. Lê li vir çi mane heye min fêm nekir. —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 10:33, 2 îlon 2020 (UTC) == [[li rûyê dinê xweş mayîn]] == Çavkaniyeke klasîk heye —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:38, 2 îlon 2020 (UTC) == [[bêsewî]] == klasîk —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 06:34, 4 îlon 2020 (UTC) == [[merkemoş]] == Klasîk —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 06:34, 4 îlon 2020 (UTC) == [[firfiroka bayî]] == {{r|Mamoste Dilovan}} ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:57, 6 îlon 2020 (UTC) == [[guhê fîlî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:56, 7 îlon 2020 (UTC) : {{r|Bikarhêner}} Min guh li evê peyvê bû ji kesekî ku xudan xwaringehek û baxçeyekî mezin e. : Gelek tişt di berbelav in û xelk dizanin, lê di pertûkan de naye dîtin. {{bêîmze|IbrahimKocher Duhok}} == [[gurovî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:41, 14 îlon 2020 (UTC) :{{r|Bikarhêner}} Çavkanîyên peyvên ku min nivîsandin mixabin ne nivîskî ne. Ev peyv min ji hin mezinên malbatê bihîstine û min jî gelek caran dîtîne ku hatine bikaranîn. Ji bo ku ev peyv wûnda nebin min hem li ba xwe û hem jî li wîkîferhengê nivîsand. Ji bo peyvên ku çavkanîyên nivîskî tunin, mixabin gotinên devkî tene weke çavkanî dimînin. Pêşnîyara te ji bo pevên bi vî awayî çi ye gelo? Spas{{bêîmze|Xwende}} ::{{r|Xwende}} Pêşî li ser malpera [https://tirsik.net/xerhati.php] dûre jî li ser arsiv.org qeyd bike ku nikarî çavkanî peyda bikî. Herwiha bnr [[Alîkarî:Îmze]] --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:00, 15 îlon 2020 (UTC) == [[şîloyî]] == {{r|Xwende}} ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:44, 14 îlon 2020 (UTC) == [[dever]] == Ji bo wateya ''derence, sêlim û merdîwen'' [[Wîkîferheng:Pîvekên tevlîkirinê|çavkanî hewce ye]]. —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:53, 14 îlon 2020 (UTC) == [[kerrnizî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 15:56, 15 îlon 2020 (UTC) == [[li dora (yekê) gerîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:46, 15 îlon 2020 (UTC) == [[glas]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]. --[[Bikarhêner:Şêr|Şêr]] ([[Gotûbêja bikarhêner:Şêr|gotûbêj]]) 12:45, 16 îlon 2020 (UTC) == [[kejmûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:42, 17 îlon 2020 (UTC) == [[lirêgerîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:20, 18 îlon 2020 (UTC) == [[çavpeqî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:23, 23 îlon 2020 (UTC) :http://www.geocities.ws/mehname2004a/63/pexsan5.html -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 16:58, 23 îlon 2020 (UTC) == [[çavpeqiyayî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:14, 23 îlon 2020 (UTC) :{{r|Balyozxane}} Çavpeqî û -iyayî eynî peyv in, heke bo nimûne 2 çavkanî ji bo çavpeqî û 1 ji bo -iyayî werin dîtin ew weke 3 ji bo yek peyv tên jimartin? -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:16, 23 îlon 2020 (UTC) ::{{r|Guherto}}. Na, divê yek ji wan peyitandî be daku em karibin yek ji wan wek guherto nîşan bidin. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:45, 23 îlon 2020 (UTC) :::Temam naxwe. {{=(}} -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:48, 23 îlon 2020 (UTC) ::::Ecêb e peyva çavpeqîn jî tune ye. Divê çavpeqî/çavpeqiyayî jê hatibe lê qet tune. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:56, 23 îlon 2020 (UTC) :::::Em çavpeqî ne weke kesekî ku çavê wan peqî ye dibêjin. Siqêfek e. ''Wilo neke, çavpeqî!'' -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 18:10, 23 îlon 2020 (UTC) == [[olfatûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:58, 24 îlon 2020 (UTC) :Du çavkanî hatiye dîtin li hêviya ya sisêyan e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:46, 23 sibat 2025 (UTC) == [[hekûke]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:00, 28 îlon 2020 (UTC) :Tenê çavkaniyek ji Kovara Kurmancî heye ew jî ji kitêba Gundê Mêrxasan a Eliyê Evdilrehman hatiye girtin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:49, 23 sibat 2025 (UTC) == [[dê bêjî kaya di serî de]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:58, 29 îlon 2020 (UTC) == [[heçî ne li malekê, nizanit halekê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:58, 29 îlon 2020 (UTC) == [[heta nîva destî reş nebit, tama devî xoş nabit]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:58, 29 îlon 2020 (UTC) == [[kirtop]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Herwiha [[kirtope]]—[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:59, 29 îlon 2020 (UTC) : == [[pişkûmişk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 21:25, 29 îlon 2020 (UTC) = Çiriya pêşîn 2020 = == [[ma te şulê pê ye?]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:19, 1 çiriya pêşîn 2020 (UTC) == [[zelam yêt heyn û zelamoşk jî yêt heyn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:28, 1 çiriya pêşîn 2020 (UTC) == [[ezîz î&#59; ji pêrve ne mîzî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:15, 1 çiriya pêşîn 2020 (UTC) == [[qelpez]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 08:19, 6 çiriya pêşîn 2020 (UTC) == [[firêzer]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 15:27, 6 çiriya pêşîn 2020 (UTC) == [[kirmişk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 09:03, 7 çiriya pêşîn 2020 (UTC) == [[orijîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 19:03, 7 çiriya pêşîn 2020 (UTC) == [[şequdeq]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 08:50, 9 çiriya pêşîn 2020 (UTC) == [[helizandin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 11:23, 9 çiriya pêşîn 2020 (UTC) == [[rewastin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 11:48, 9 çiriya pêşîn 2020 (UTC) == [[xunaftin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:31, 9 çiriya pêşîn 2020 (UTC) == [[itîmad li ser kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 16:32, 15 çiriya pêşîn 2020 (UTC) == [[sengesor]] == {{r|Saberabdollahizad}} ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:00, 16 çiriya pêşîn 2020 (UTC) :Navçeya Mirgewerê, Ûrmîye. {{bêîmze|Saberabdollahizad}} == [[zenek]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:03, 16 çiriya pêşîn 2020 (UTC) :{{r|Saberabdollahizad}} [[zenek]] jî li Ûrmiyê tê bikaranîn? --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 19:53, 18 çiriya pêşîn 2020 (UTC) == [[pind#p-mane|pind]] == Min tenê çavkaniyek dît ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:48, 17 çiriya pêşîn 2020 (UTC) :Navçeya Mirgewerê, Ûrmîye. {{bêîmze|Saberabdollahizad}} == [[maqezer]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:53, 18 çiriya pêşîn 2020 (UTC) :Navçeya Mirgewerê, Ûrmîye. {{bêîmze|Saberabdollahizad}} == [[pezpezok]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:55, 18 çiriya pêşîn 2020 (UTC) :Navçeya Mirgewerê, Ûrmîye. {{bêîmze|Saberabdollahizad}} == [[parapet#p-mane|parapet]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:53, 31 çiriya pêşîn 2020 (UTC) = Çiriya paşîn 2020 = == [[quloç#p-mane|quloç]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:43, 19 çiriya paşîn 2020 (UTC) == [[di ber (yekî) de avêtin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:57, 20 çiriya paşîn 2020 (UTC) :https://tirsik.net/index.php?mijarid=18749&iro=on&rupel=1 —[[Bikarhêner:Mamoste Dilovan|Mamoste Dilovan]] ([[Gotûbêja bikarhêner:Mamoste Dilovan|gotûbêj]]) 17:37, 20 çiriya paşîn 2020 (UTC) :: {{r|Mamoste Dilovan}} [[di ber re avêtin]] heye. lê te wek di ber '''de''' lê zêde kir. Em biguherînin? Gelek çavkanî ji bo di ber re avêtin heye. --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:41, 20 çiriya paşîn 2020 (UTC) == [[hêvastin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 10:49, 21 çiriya paşîn 2020 (UTC) == [[lamçîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 11:28, 22 çiriya paşîn 2020 (UTC) == [[poz#p-mane|poz]] == Ji bo maneya "[[quz]], [[vajîna]]" ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 11:28, 22 çiriya paşîn 2020 (UTC) == [[sihetbexş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:35, 24 çiriya paşîn 2020 (UTC) == [[hevjêhatin ji jêhatîbûnê çêtir e]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:14, 25 çiriya paşîn 2020 (UTC) == [[gerriyan#p-mane|gerriyan]] == ''Ji bo wateya cereyan (tevger)''. Qasî ku dibînim tenê Cewerî bi kar aniye —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:24, 25 çiriya paşîn 2020 (UTC) == [[derbend]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:08, 30 çiriya paşîn 2020 (UTC) = Kanûna paşîn 2021 = == [[desthelgirtin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:48, 6 kanûna paşîn 2021 (UTC) == [[êşewî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:52, 7 kanûna paşîn 2021 (UTC) == [[sexorr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:22, 7 kanûna paşîn 2021 (UTC) == [[sapût]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:06, 12 kanûna paşîn 2021 (UTC) == <s>[[dimorî]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Maneya navdêrî bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:05, 20 kanûna paşîn 2021 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:18, 26 hezîran 2026 (UTC) :Di Kovara kurmancî hj.67 de "dimor" bi maneya "bêoxir" de derbas dibe. Wekî din ti çavkanî nîne. Merheba @[[Bikarhêner:Gomada|Gomada]] te varyanta "dimhorî" îlawe kiriye. Gelo tu dizanî ev kelîme li kîjan herêman tê bikaranîn? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:18, 26 hezîran 2026 (UTC) = Çiriya pêşîn 2022 = == [[paşbingeh]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 07:40, 12 çiriya pêşîn 2022 (UTC) = Kanûna paşîn 2023 = == [[berê beringa]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:35, 1 kanûna paşîn 2023 (UTC) == [[mûlûleya xwînê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:36, 6 kanûna paşîn 2023 (UTC) == [[mirovdostî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 05:38, 12 kanûna paşîn 2023 (UTC) == [[derîner]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 23:02, 15 kanûna paşîn 2023 (UTC) == [[neteba]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 00:01, 16 kanûna paşîn 2023 (UTC) :Maneya "uyruksuz" ji ferhenga Farqînî hatiye kopîkirin wekî din bi giştî bi maneya "nakokî" tê bikaranîn. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:33, 26 hezîran 2026 (UTC) == [[narkotîkfiroş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 10:59, 16 kanûna paşîn 2023 (UTC) == [[pirik#p-mane|pirik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:15, 16 kanûna paşîn 2023 (UTC) == [[ramyarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ez dibêjim ev peyv tenê bi maneya "fikrî", wek rengdêr heye. Lê belê di soranî de bi şaşemilandineke wekî "siyasî" bi kar anîne, kurmancên me jî rasterast maneya soranî tevlî çend ferhengên hev-kopîkirî kirine û bi vî awayî belkî hin çavkanî hebin. Lê ez dibêjim divê ew çavkanî jî neyên hesibandin. Hin kes zen dikin ku her tiştê di soranî de ripîrast e. Mesele heqeten eletewş e. Agahiyeke li ser peyvê: "[https://www.welateme.info/kurdi/modules.php?name=News&file=print&sid=686 Welateme.info]" Li vir peyv bi maneya "fikrî" hatiye bikaranîn: "[https://xwebun1.org/ziman-sirhelal-e/ Xwebûn]". Qewet be. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:36, 19 kanûna paşîn 2023 (UTC) == [[dolîwgeh]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:08, 22 kanûna paşîn 2023 (UTC) = Sibat 2023 = == [[herebaş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:13, 11 sibat 2023 (UTC) == [[balindeyê korare]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê çavkaniyekê tê xuyan, ew jî kitêba "Balindeyên Kurdistanê" yê Îsmaîl Taha Şahîn e (Îsmaîl Taha Şahîn (2006). Balindeyên Kurdistanê, 1-4. Spîrêz, Duhok). Ev kitêb ji ser înternetê wek word jî peyda dibe. Xuya ye ku ji Weşanên Spîrez fîzîken jî çap bûye. Lê wekî çavkanî tenê ev tê xuyan. —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:10, 14 sibat 2023 (UTC) == [[dîbeyt]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:13, 18 sibat 2023 (UTC) == [[çend pat]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:35, 24 sibat 2023 (UTC) == [[rabînîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ji bo kurmancî bêçavkanî ye. Ger ji bo soranî çavkanî hebin jî divê ji bo soranî bi herfên aramî were nivîsîn. An ger halê latînîkirî ya peyveke soranî be, dîsa divê ev hal were eşkerekirin. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:36, 26 sibat 2023 (UTC) = Adar 2023 = == [[qirar#p-mane|qirar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:23, 2 adar 2023 (UTC) == [[pîşpêkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê di nivîseke online ya Cemal Nebez de derbas dibe. Dibe ku peyveke başûriyan be. Û di wê nivîsa Cemal Nebezê bi forma "pîş bi ... bikin" jî derbas dibe. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:29, 3 adar 2023 (UTC) == [[kûcag]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:27, 27 adar 2023 (UTC) == [[destbizavî kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Xuya ye ku ev peyv tenê di kitêba “''Nameyek Şernexê''” yê Evdirehman Gundikî de derbas bûye. Û ji wir jî Mistefa Aydoganî maneya peyvê di hejmara 61em ya Kovara ''Kurmancî'' de belav kiriye (rûpela 2yem). Lê belê tenê yek çavkaniyekê ne bes e ji bo ku em vê peyvê di vê ferhengê de wekî peyveke çavkanî-temam belav bikin. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:40, 28 adar 2023 (UTC) == [[germav baş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:23, 31 adar 2023 (UTC) == [[germavxweş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:27, 31 adar 2023 (UTC) = Gulan 2023 = == [[kirbend]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 08:34, 5 gulan 2023 (UTC) : Çêkerê rûpelê wek not nivîsiye ku peyv ji herêma Çewlikê ye. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 06:24, 6 gulan 2023 (UTC) == [[We are off now]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:13, 22 gulan 2023 (UTC) == [[baran ji erd û esmana lê diket]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:46, 26 gulan 2023 (UTC) == [[sîba]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:44, 30 gulan 2023 (UTC) == [[bîrîner]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:20, 30 gulan 2023 (UTC) = Hezîran 2023 = == [[bidestmiz]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:49, 10 hezîran 2023 (UTC) = Tîrmeh 2023 = == [[parzeng]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:01, 15 tîrmeh 2023 (UTC) == [[zerpedest]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:05, 15 tîrmeh 2023 (UTC) == [[heta destên mirov nebine gû, devê mirov nabite tû]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:27, 19 tîrmeh 2023 (UTC) == [[çemê mezin tê dibore diçe]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:38, 19 tîrmeh 2023 (UTC) == [[kevanê nebî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:45, 19 tîrmeh 2023 (UTC) == [[teybûr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê li malpera yuksekovahaber.com-ê derbas dibe, li wir jî bi maneya "çare, çareserî"yê hatiye emilandin, ne bi vê maneyê. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:00, 19 tîrmeh 2023 (UTC) == [[nikêtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:22, 19 tîrmeh 2023 (UTC) = Tebax 2023 = == [[prêze]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 21:19, 15 tebax 2023 (UTC) == [[qelye]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 15:59, 25 tebax 2023 (UTC) = Îlon 2023 = == [[hetwan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:21, 14 îlon 2023 (UTC) == [[milyonmasî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:06, 21 îlon 2023 (UTC) == [[tofana mêjî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:20, 21 îlon 2023 (UTC) == [[îshaf]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 10:57, 23 îlon 2023 (UTC) == [[odeya karkirinê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 10:57, 26 îlon 2023 (UTC) == [[odeya şixulînê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 11:42, 26 îlon 2023 (UTC) == [[hîter]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:08, 26 îlon 2023 (UTC) = Çiriya pêşîn 2023 = == [[vîtamîn waw]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:20, 1 çiriya pêşîn 2023 (UTC) == [[berhan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:21, 3 çiriya pêşîn 2023 (UTC) == [[sêlikdêr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:16, 10 çiriya pêşîn 2023 (UTC) == [[qewandêr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:20, 10 çiriya pêşîn 2023 (UTC) == [[darav]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:04, 11 çiriya pêşîn 2023 (UTC) = Çiriya paşîn 2023 = == [[kansernasî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:54, 14 çiriya paşîn 2023 (UTC) == [[golgir]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:06, 15 çiriya paşîn 2023 (UTC) == <s>[[gogpî]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 16:19, 15 çiriya paşîn 2023 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:17, 24 tîrmeh 2026 (UTC) == [[ahardar]] == Tenê Zana Farqînî —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 10:34, 26 çiriya paşîn 2023 (UTC) = Kanûna pêşîn 2023 = == [[Kî mal ezîz bike, can rezîl dike&#59; kî mal rezîl bike, can ezîz dike.]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:55, 2 kanûna pêşîn 2023 (UTC) == [[porsing]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:22, 2 kanûna pêşîn 2023 (UTC) == [[newelatî kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:57, 2 kanûna pêşîn 2023 (UTC) == [[newelatîkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:58, 2 kanûna pêşîn 2023 (UTC) == [[alîkar kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Şêr|Şêr]] ([[Gotûbêja bikarhêner:Şêr|gotûbêj]]) 18:42, 3 kanûna pêşîn 2023 (UTC) == [[aramoş kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'' -- [[Bikarhêner:Şêr|Şêr]] ([[Gotûbêja bikarhêner:Şêr|gotûbêj]]) 18:48, 3 kanûna pêşîn 2023 (UTC) == [[bêvil kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Şêr|Şêr]] ([[Gotûbêja bikarhêner:Şêr|gotûbêj]]) 18:56, 4 kanûna pêşîn 2023 (UTC) == [[dijberiya naverokî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Şêr|Şêr]] ([[Gotûbêja bikarhêner:Şêr|gotûbêj]]) 22:43, 8 kanûna pêşîn 2023 (UTC) == [[bersivîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]]'', û her wiha ne li gorî qayideyên kurdî (kurmancî) ye. —[[Bikarhêner:Şêr|Şêr]] ([[Gotûbêja bikarhêner:Şêr|gotûbêj]]) 22:08, 11 kanûna pêşîn 2023 (UTC) == <s>[[girêbanasî]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:30, 13 kanûna pêşîn 2023 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:18, 24 tîrmeh 2026 (UTC) == [[hevalzewac]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:25, 18 kanûna pêşîn 2023 (UTC) = Kanûna paşîn 2024 = == [[raperk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:40, 15 kanûna paşîn 2024 (UTC) :Bi wê manê nîne. Bi maneke dî heye. [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 19:26, 6 tebax 2024 (UTC) = Sibat 2024 = == [[bi navê lîstin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:02, 3 sibat 2024 (UTC) : Li ser agahdarkirina çêkerê rûpelê me şablona "dever"ê tevlî kir. Peyv ji herêma Qoser, Mêrdînê ye. Me li qismê "Bikaranîn"ê jî vê yekê dîyar kir. Ji xeynî vê me wê peyvê ji rûpelên din jî bir. Bi vî awayî ev made kare were girtin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:28, 10 nîsan 2024 (UTC) == <s>[[firoşgehkar]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:17, 9 sibat 2024 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 24 tîrmeh 2026 (UTC) == [[preskirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:43, 11 sibat 2024 (UTC) == [[pres kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:43, 11 sibat 2024 (UTC) == [[Xwedê te têr bike]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:41, 13 sibat 2024 (UTC) == [[isad]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:09, 22 sibat 2024 (UTC) == [[razemendîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:44, 27 sibat 2024 (UTC) = Adar 2024 = == [[zilhêzî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:19, 5 adar 2024 (UTC) == [[hingihîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:32, 13 adar 2024 (UTC) == [[xore]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:30, 15 adar 2024 (UTC) == [[melef]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:55, 19 adar 2024 (UTC) == [[uğursuz ayak]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:11, 23 adar 2024 (UTC) == [[şepûk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:22, 23 adar 2024 (UTC) == [[agirberdêrî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 00:04, 26 adar 2024 (UTC) == [[kîrquz]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:00, 26 adar 2024 (UTC) == [[kîrquzdê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:01, 26 adar 2024 (UTC) == [[quzgêj]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:03, 26 adar 2024 (UTC) = Nîsan 2024 = == [[hîkarîkerî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:53, 1 nîsan 2024 (UTC) == [[hîkarîker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:54, 1 nîsan 2024 (UTC) == [[hîkarîdarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:55, 1 nîsan 2024 (UTC) == [[hîkarîdar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:56, 1 nîsan 2024 (UTC) == [[bihîkarîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:57, 1 nîsan 2024 (UTC) == [[bihîkarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:58, 1 nîsan 2024 (UTC) == [[bêhîkarîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:58, 1 nîsan 2024 (UTC) == [[bêhîkarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:59, 1 nîsan 2024 (UTC) == [[bêhîkarî bûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:00, 1 nîsan 2024 (UTC) == [[bêhîkarî kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:00, 1 nîsan 2024 (UTC) == [[bêhîkarîbûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:01, 1 nîsan 2024 (UTC) == [[bêhîkarîkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:01, 1 nîsan 2024 (UTC) == [[hîkarîkirî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:02, 1 nîsan 2024 (UTC) == [[hîkarîkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:03, 1 nîsan 2024 (UTC) == [[hîkarî kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:07, 1 nîsan 2024 (UTC) == [[rayda]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:40, 1 nîsan 2024 (UTC) == [[bêrayda]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:42, 1 nîsan 2024 (UTC) == [[bêraydayî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:43, 1 nîsan 2024 (UTC) == [[bêraydatî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:43, 1 nîsan 2024 (UTC) == [[bêrayda bûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:43, 1 nîsan 2024 (UTC) == [[bêrayda kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:43, 1 nîsan 2024 (UTC) == [[bêraydabûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:44, 1 nîsan 2024 (UTC) == [[bêraydakirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:44, 1 nîsan 2024 (UTC) == [[birayda]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:44, 1 nîsan 2024 (UTC) == [[biwerêç]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:46, 1 nîsan 2024 (UTC) == [[biwerêçî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:46, 1 nîsan 2024 (UTC) == [[biwerêçîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:47, 1 nîsan 2024 (UTC) == [[biwerêçtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:47, 1 nîsan 2024 (UTC) == [[werêç]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:49, 1 nîsan 2024 (UTC) == [[werêç kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 1 nîsan 2024 (UTC) == [[werêçkirî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 1 nîsan 2024 (UTC) == [[werêçkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:51, 1 nîsan 2024 (UTC) == [[wişto]] == @[[Bikarhêner:Zerwanda]] Çavkanî ji bo kurmancî tine ye. Zazakî ye? —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:19, 1 nîsan 2024 (UTC) :ji devera mûşê, aliyê diya min "wişto/wiştik" digotin. [[Bikarhêner:Zerwanda|Zerwanda]] ([[Gotûbêja bikarhêner:Zerwanda|gotûbêj]]) 20:44, 1 nîsan 2024 (UTC) == [[xewgerî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:19, 2 nîsan 2024 (UTC) == [[xewgerokî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:28, 2 nîsan 2024 (UTC) == [[nimêh]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:51, 2 nîsan 2024 (UTC) == [[فعال]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' [[Bikarhêner:Ghybu|Gyhbu]] di 2021an de li ser rûpela wî tevlî kirîye. Lê ji ber nebûna vê sîstema me tevlî vir nebûye. Lewma min anî ser vir jî. Wê gavê tenê ji bo maneya "kar" ev şablon hatîye tevlîkirin. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 07:27, 3 nîsan 2024 (UTC) == [[pêjor]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:46, 6 nîsan 2024 (UTC) == [[hafil]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:48, 6 nîsan 2024 (UTC) == [[micemi]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Muhtemelem şiklê rast wek "micemî" ye, lê ew jî bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:52, 9 nîsan 2024 (UTC) == [[hesaba xwe]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ji xeynî van ev forma wê jî bêçavkanî ne: "[[hisaba xwe]] / [[hesaba xo]] / [[hisaba xo]]". — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:25, 9 nîsan 2024 (UTC) == [[leşkerma]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:53, 24 nîsan 2024 (UTC) = Gulan 2024 = == [[serîi]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Wek "serî" belkî li kar be, lê wekî "serîi" çavkanî peyda nabe. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:20, 2 gulan 2024 (UTC) == [[virgu]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Bêçavkanî tê xuyan. Peyv bi tirkî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:49, 2 gulan 2024 (UTC) == [[xwerre]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:57, 20 gulan 2024 (UTC) = Hezîran 2024 = == [[di nav deryaya peyvan de avjenî dikir]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:34, 4 hezîran 2024 (UTC) == [[berbixwe]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:03, 10 hezîran 2024 (UTC) == [[şipyakî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:08, 10 hezîran 2024 (UTC) :"şipêkî" heye [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 20:20, 27 tîrmeh 2024 (UTC) == [[wetalane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:18, 10 hezîran 2024 (UTC) == [[wetalî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:19, 10 hezîran 2024 (UTC) == [[wetalîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:20, 10 hezîran 2024 (UTC) == [[wetaltî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:20, 10 hezîran 2024 (UTC) == [[se direye karwan dibuhire]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:49, 16 hezîran 2024 (UTC) == [[se direwît, karwan bi rêka xo diçît]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Formeke bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:53, 16 hezîran 2024 (UTC) == [[se direwît, karwan diburît]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Formeke bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:54, 16 hezîran 2024 (UTC) == [[se direyê karwan dibûrê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Formeke bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:55, 16 hezîran 2024 (UTC) == [[se direye karvan li riya xwe diçe]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Formeke bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:56, 16 hezîran 2024 (UTC) == [[se direye û kerwan dibihure]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Formeke bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:00, 16 hezîran 2024 (UTC) == [[hingê dinya]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:07, 18 hezîran 2024 (UTC) == [[berdanberdan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:22, 24 hezîran 2024 (UTC) == [[nîska mala Barzan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:05, 25 hezîran 2024 (UTC) = Tîrmeh 2024 = == [[avmêwe]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:41, 16 tîrmeh 2024 (UTC) == [[nihalok]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:53, 24 tîrmeh 2024 (UTC) == [[nihalk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:54, 24 tîrmeh 2024 (UTC) == [[niwalok]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:54, 24 tîrmeh 2024 (UTC) == [[niwalk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:55, 24 tîrmeh 2024 (UTC) == [[niwalik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:55, 24 tîrmeh 2024 (UTC) == [[nehalok]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:56, 24 tîrmeh 2024 (UTC) == [[nehalk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:56, 24 tîrmeh 2024 (UTC) == [[nehalik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:57, 24 tîrmeh 2024 (UTC) == [[alîkarxwazî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:16, 24 tîrmeh 2024 (UTC) == [[nihalik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:19, 24 tîrmeh 2024 (UTC) == [[zêrîb]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Bi dîtina min, ev form bêçavkanî ye. Dibe ku ji bo forma "zerîb" çavkanî hebe, lê ew form li ser Wîkîferhengê wek made nehatîye çêkirin. Pir kêm be jî ev peyv wek "zerîp" jî li cihekî derbas bûye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:31, 24 tîrmeh 2024 (UTC) == [[qanat]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ev peyv bi maneya "kanal"ê nîne, xelet e. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 06:59, 25 tîrmeh 2024 (UTC) == [[qenat]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ev peyv bi maneya "kanal"ê nîne, xelet e. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 06:59, 25 tîrmeh 2024 (UTC) :Min 1 çavkanî dît, "Ev kes rojê 6-7 qenatên TV ya diğere û diaxive" https://darkamazi.info/archives/1019704 (bi lêgerana "qenatên", ji ber ko lêgeranên dî tijî tiştên dî derdixin) :Lê mimkun e xelet nivîsîbe. [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 20:31, 27 tîrmeh 2024 (UTC) == [[şkaftmend]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 07:08, 25 tîrmeh 2024 (UTC) :3 çavkanî hene. Lê xuya dike jêdera wan hemû ferhenga tirsik.netê e. :* Çavkanî 1: https://tirsik.net/ferheng?query=şkaftmend (berî 2014, lê tarîx nîne) :* Çavkanî 2: https://ku.wikipedia.org/wiki/Deranderî (2011) :* Çavkanî 3: https://x.com/zerdeceno/status/1155331427510247425 (2019) :[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 20:28, 27 tîrmeh 2024 (UTC) == [[dan hev#p-mane|dan hev]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ev mane li ser çavkanîyan peyda nabe. Tenê çêkerê rûpelê vê maneyê nivîsîye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:08, 25 tîrmeh 2024 (UTC) == [[baristdar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:47, 25 tîrmeh 2024 (UTC) == [[baristdarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:48, 25 tîrmeh 2024 (UTC) == [[baristdarîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:49, 25 tîrmeh 2024 (UTC) == [[baristdartî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:50, 25 tîrmeh 2024 (UTC) == [[bibaristî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:51, 25 tîrmeh 2024 (UTC) == [[bibarist]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:52, 25 tîrmeh 2024 (UTC) == [[bibaristîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:53, 25 tîrmeh 2024 (UTC) == [[bêbaristî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:54, 25 tîrmeh 2024 (UTC) == [[bêbarist]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:55, 25 tîrmeh 2024 (UTC) == [[peydabûnîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 20:52, 27 tîrmeh 2024 (UTC) == [[nexşvan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 21:05, 27 tîrmeh 2024 (UTC) == [[nexşvanî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 21:05, 27 tîrmeh 2024 (UTC) == [[lêvikî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 21:47, 27 tîrmeh 2024 (UTC) == [[lêvik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Min zêde nemeyzand. —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 21:48, 27 tîrmeh 2024 (UTC) == [[şerenîx kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 21:51, 27 tîrmeh 2024 (UTC) == [[sala çîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:09, 29 tîrmeh 2024 (UTC) == [[berê pêşîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:57, 30 tîrmeh 2024 (UTC) == [[berê ewilî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:57, 30 tîrmeh 2024 (UTC) = Tebax 2024 = == [[xwîndijmin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:02, 4 tebax 2024 (UTC) == [[reîsîtî]]/[[reysîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 18:17, 6 tebax 2024 (UTC) == [[soranîaxivî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 18:43, 6 tebax 2024 (UTC) == [[helîna bildo]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ji 2020a ve şablon li wir e min tenê li vir zêde kir. —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 19:56, 6 tebax 2024 (UTC) == [[hilbijêrînerî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' "Hilbij" rihê peyvê ye, "-er" jî maneya "kesê dike" dide, qertafa "-îner / -înerî" ya li dawîyê bi eşkereyî xelet e. Û ev peyv bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:45, 7 tebax 2024 (UTC) == [[îqlîmtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:43, 10 tebax 2024 (UTC) == [[jîrbêjî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ev peyv ger di soranî de ji bo wê çavkanîyên têr hebe, tenê wek "Nivîsîna bi herfên latînî ya peyva ..." kare were qeydkirin. Lê nabe ku wek kurmancî be, were qeydkirin. Ji bo kurmancî tenê di meqaleyekê de derbas dibe, ew jî ji alî başûrîyekî ve hatîye nivîsîn. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:55, 10 tebax 2024 (UTC) == [[hîgyen]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê ev form bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 07:40, 12 tebax 2024 (UTC) == [[kolîner]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:45, 12 tebax 2024 (UTC) == [[poşmanî kişîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê di çavkanîyekê de peyda dibe. Ew çavkanîya dayî jî ihtîmal e ku bi tesîra zimanê tirkî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:44, 13 tebax 2024 (UTC) == [[para hevpar a herî mezin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:09, 14 tebax 2024 (UTC) == [[cara hevpar a herî biçûk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:10, 14 tebax 2024 (UTC) == [[regjimar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:16, 14 tebax 2024 (UTC) == [[nîvrengî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:33, 18 tebax 2024 (UTC) == [[nîvdûrgeh]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Wek "guharto" hatiye qeydkirin, lê yek nikare wilo bêje. Ne "guharto" ye, ji ber wê çavkanî hewce ne. —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:39, 18 tebax 2024 (UTC) == [[nîvtewlîsî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:44, 18 tebax 2024 (UTC) == [[nîvrewa]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:44, 18 tebax 2024 (UTC) == [[nîvşehtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:46, 18 tebax 2024 (UTC) == [[nîvfalincî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:46, 18 tebax 2024 (UTC) == [[nîvgilkarî]] == Ferhenga Sa.Sa. ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 17:48, 18 tebax 2024 (UTC) == [[kesîkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 20:16, 18 tebax 2024 (UTC) == [[biryarbirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:38, 24 tebax 2024 (UTC) = Îlon 2024 = == [[qîblename]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 15:15, 1 îlon 2024 (UTC) == [[cihetnima]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ji [https://bianet.org/yazi/ferhenga-ser-u-amrazen-ser-ji-kovara-ronahiye-2-196299 vir] hatiye —[[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 15:27, 1 îlon 2024 (UTC) == [[qûnderîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:36, 7 îlon 2024 (UTC) == [[hevpîşehî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:48, 14 îlon 2024 (UTC) == [[hevpîşeyî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Wek ''navdêr'' bêçavkanî ye. Wek ''rengdêr'' hebe jî, kêmçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:50, 14 îlon 2024 (UTC) == [[hempay]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:04, 14 îlon 2024 (UTC) == [[nîs]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:43, 14 îlon 2024 (UTC) == [[êxbarçî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ji bo ''îxbarçî'' çavkanîyekê peyda dibe, lê kêm e. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:06, 14 îlon 2024 (UTC) == [[muxbîrîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:38, 14 îlon 2024 (UTC) == [[ixbarçî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:43, 14 îlon 2024 (UTC) == [[westgeha pasê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:33, 19 îlon 2024 (UTC) == [[avikmadk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:24, 19 îlon 2024 (UTC) == [[ferwerîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:18, 20 îlon 2024 (UTC) == [[bipayderî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:12, 20 îlon 2024 (UTC) == [[bipayderîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:13, 20 îlon 2024 (UTC) == [[bipaydertî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:13, 20 îlon 2024 (UTC) == [[bipedalî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:14, 20 îlon 2024 (UTC) == [[bipedalîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:14, 20 îlon 2024 (UTC) == [[bipedaltî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:14, 20 îlon 2024 (UTC) == [[pedaldarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:15, 20 îlon 2024 (UTC) == [[pedaldarîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:15, 20 îlon 2024 (UTC) == [[pedaldartî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:16, 20 îlon 2024 (UTC) == [[ciwên]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:11, 22 îlon 2024 (UTC) == [[belgebirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:31, 23 îlon 2024 (UTC) == [[avsîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Dibe ku ev kelîme biçavkanî be, lê pir bêagahî hatîye qeydkirin. Biçavkanî be jî, ji ber qeydkirina bêagahî (li ser madeyê agahî kêm hatine pêşkêşkirin) em rûpelê jê bibin. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:53, 23 îlon 2024 (UTC) :@[[Bikarhêner:Bikarhêner|Bikarhêner]] Ma ne çêtir e li "Daxwazên zelalkirinê" be naxwe? [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 13:40, 10 çiriya paşîn 2024 (UTC) :: {{r|Guherto}} Bi min em karin vê madeyê ji ber bêagahîbûna wî, îlaweyî "Daxwazên jêbirinê" bikin, lê "Daxwazên zelalkirinê" nabe. Wekî din ji ber ku dikeve çarçoveya her du rûpelan jî kîjan be jî dibe, lê madem me li vir da destpêkirin, bila ji vir dewam bike dengdana li ser vê kelîmeyê. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:22, 10 çiriya paşîn 2024 (UTC) == [[kûvank]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Herçiqas tenê formekê be jî, bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:14, 27 îlon 2024 (UTC) == [[kikark]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Herçiqas formekê be jî, bêçavkanî dixuye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:40, 27 îlon 2024 (UTC) == [[kîfkarik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Herçiqas tenê formekê be jî, bêçavkanî dixuye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:45, 27 îlon 2024 (UTC) == [[kuvank]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Herçiqas formekê be jî, bêçavkanî dixuye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:53, 27 îlon 2024 (UTC) == [[kûvarik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Herçiqas tenê formekê be jî, bêçavkanî dixuye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:01, 27 îlon 2024 (UTC) = Çiriya pêşîn 2024 = == [[muhil]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê qismê kurdî bêçavkanî ye, ne ya tirkî. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:00, 9 çiriya pêşîn 2024 (UTC) == [[muhilk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:00, 9 çiriya pêşîn 2024 (UTC) == [[jêrmal]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:59, 15 çiriya pêşîn 2024 (UTC) = Çiriya paşîn 2024 = == [[bîrxistiner]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 19:38, 14 çiriya paşîn 2024 (UTC) == [[wisa gotin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ne ferhengî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:13, 15 çiriya paşîn 2024 (UTC) == [[tenzîlatî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:12, 16 çiriya paşîn 2024 (UTC) == [[armancparêz]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:03, 19 çiriya paşîn 2024 (UTC) == [[şikaftmend]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:06, 19 çiriya paşîn 2024 (UTC) == [[derander]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:08, 19 çiriya paşîn 2024 (UTC) == [[deranderî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 13:09, 19 çiriya paşîn 2024 (UTC) == [[derxwenîn]] == @[[User:Keyomerd]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 22:38, 19 çiriya paşîn 2024 (UTC) == [[kiyû]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 23:53, 22 çiriya paşîn 2024 (UTC) == [[goçavik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 00:03, 23 çiriya paşîn 2024 (UTC) == [[hûrhesibaner]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 00:19, 23 çiriya paşîn 2024 (UTC) == [[heybera zindî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:01, 23 çiriya paşîn 2024 (UTC) == [[misadereker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:51, 24 çiriya paşîn 2024 (UTC) == [[kêmtirkar]] == @[[Bikarhêner:Cyrus the virus|Cyrus the virus]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:11, 24 çiriya paşîn 2024 (UTC) == [[cudagir]] == @[[Bikarhêner:Cyrus the virus|Cyrus the virus]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:15, 24 çiriya paşîn 2024 (UTC) == [[qerwaşgir]] == @[[Bikarhêner:Cyrus the virus|Cyrus the virus]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:42, 24 çiriya paşîn 2024 (UTC) == [[mişkilûr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:45, 24 çiriya paşîn 2024 (UTC) == [[agirbiran]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:54, 24 çiriya paşîn 2024 (UTC) == [[alan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:55, 24 çiriya paşîn 2024 (UTC) == [[alêdû]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 18:56, 24 çiriya paşîn 2024 (UTC) == [[henaseker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 17:37, 25 çiriya paşîn 2024 (UTC) == [[nial]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ji xeynî vê, maneya 2yem ya di madeya "nihal" de (navdêr 2) jî bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:46, 27 çiriya paşîn 2024 (UTC) == [[gilçim]] == @[[Bikarhêner:Roj Rewandiz|Roj Rewandiz]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:28, 29 çiriya paşîn 2024 (UTC) :Ez ji bajarê Kobaniyê me. Min ev peyv ji ser zimanê dê û dapîra xwe girt. Ez gelekî ji vê peyvê bawer im ji ber ku devoka min e. [[Bikarhêner:Roj Rewandiz|Roj Rewandiz]] ([[Gotûbêja bikarhêner:Roj Rewandiz|gotûbêj]]) 19:14, 23 kanûna pêşîn 2024 (UTC) ::@[[Bikarhêner:Roj Rewandiz|Roj Rewandiz]] Mala te ava. Ji ber ku çavkaniyên nivîskî tine ne em ê vê kelîmeyê wek [[Wîkîferheng:Pîvekên_tevlîkirinê#Peyvên_herêmî|herêmî]] nîşan bidin. [[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 12:22, 25 kanûna pêşîn 2024 (UTC) == [[reşeme kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Li gorî çêkera sayfeyê li Kobaniyê li kar e. Loma dikare wekî herêmî nîşankirin —[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 14:35, 29 çiriya paşîn 2024 (UTC) :Li Kobaniyê dibêjin: ‘Tizbiyê min li xwe reş û reşeme kir’ Anko Tizbî bir û venegerand Înkar kir. [[Bikarhêner:Roj Rewandiz|Roj Rewandiz]] ([[Gotûbêja bikarhêner:Roj Rewandiz|gotûbêj]]) 23:48, 7 kanûna paşîn 2025 (UTC) = Kanûna pêşîn 2024 = == <s>[[pênckunc]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:20, 27 kanûna pêşîn 2024 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:37, 17 tîrmeh 2026 (UTC) == [[çarkunc]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:21, 27 kanûna pêşîn 2024 (UTC) == <s>[[şeşkunc]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:21, 27 kanûna pêşîn 2024 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:38, 17 tîrmeh 2026 (UTC) = Kanûna paşîn 2025 = == [[pevnatî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ev kelîme wek kurtkirina ji "bi hev nehatî" hatîye fikirîn, ihtimal e ku wek sunî hatîye çêkirin û bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:43, 6 kanûna paşîn 2025 (UTC) == [[lihevnatîbûn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Wek formeke "lihevnehatîbûn"ê hatîye fikirîn, lê bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:49, 6 kanûna paşîn 2025 (UTC) == <s>[[fîzîkîtî]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:19, 7 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:42, 17 tîrmeh 2026 (UTC) == <s>[[kobar]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:59, 21 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:11, 17 tîrmeh 2026 (UTC) == <s>[[werdanbar]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:59, 21 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:10, 17 tîrmeh 2026 (UTC) == [[Binxetê]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Em zanin ku ji ber sînora Tirkîyeyê ku Cizîrê dike du perçe û ji parçeya binî re Binxet tê gotin ku kurd lê dijîn. Feqet min herêma Binxetê seh nekirîye, û bi tedqîqeke neberfireh jî çavkanî peyda nekir ji bo vê peyvê. Lewma bi min mahîyeta vê madeyê û qeydkirina wek "Binxetê" xelet e. Ger ji bo herêma tarîfkirî çavkanî nîn be, em vê madeyê bikin "'''Binxet'''" û tarîfa wê jî bikin "''Navê Rojavayê Kurdistanê ku li binê xeta Tirkîye - Sûrîyeyê dimîne.''" — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:22, 24 kanûna paşîn 2025 (UTC) == [[xirecir çêkirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' "''Çê''" bi maneya "''baş''" e, û "''çêkirin''" ji bo tiştên pozîtîv likar e, li nav milet jî ev wisa ye. Lewma ev xelet e. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:00, 24 kanûna paşîn 2025 (UTC) == [[sîrkxane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:30, 26 kanûna paşîn 2025 (UTC) == <s>[[rewanwerziş]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:33, 26 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:11, 17 tîrmeh 2026 (UTC) == <s>[[rewanwerzişxane]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:34, 26 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:12, 17 tîrmeh 2026 (UTC) == <s>[[qeşaşîrxane]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:36, 26 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 17 tîrmeh 2026 (UTC) == <s>[[tiwaletxane]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:37, 26 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 17 tîrmeh 2026 (UTC) == [[anînder]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Di hin çavkanîyan de wek formeke "''der'''''anîn'''"ê hatîye qeydkirin. Lê belê çavkanîyeke eslî (ne ji kitêbên gramerê) peyda nabe ji bo vê kelîmeyê. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:24, 27 kanûna paşîn 2025 (UTC) == [[rastî nîşandan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:14, 30 kanûna paşîn 2025 (UTC) = Sibat 2025 = == [[pir hindik#p-mane|pir hindik]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:31, 3 sibat 2025 (UTC) == <s>[[navçegir]]</s> == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:15, 4 sibat 2025 (UTC) : Zana farqînî ji xeynî wî çavkanî nîne, çend xeberên anonîm bi forma navçegirî heye lê ew jî têr nake. {{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:47, 17 tîrmeh 2026 (UTC) == [[anteroz]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:19, 15 sibat 2025 (UTC) == [[veşidandin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:43, 15 sibat 2025 (UTC) == [[karîwer kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 02:01, 16 sibat 2025 (UTC) == [[hil girtin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:06, 17 sibat 2025 (UTC) == [[wer girtin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:07, 17 sibat 2025 (UTC) == [[avkûre]] == @[[Bikarhêner:Mohajeer|Mohajeer]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:36, 18 sibat 2025 (UTC) == [[derdek girtin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:42, 18 sibat 2025 (UTC) == [[vekitandin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:12, 21 sibat 2025 (UTC) == [[dînperist]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:32, 22 sibat 2025 (UTC) == [[ayînperist]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:33, 22 sibat 2025 (UTC) == [[ayînperistî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:33, 22 sibat 2025 (UTC) == [[ayînperistane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:33, 22 sibat 2025 (UTC) == [[piştrastkirinbar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 01:45, 23 sibat 2025 (UTC) == [[diyarkirinbar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 02:08, 23 sibat 2025 (UTC) == [[hevhatî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 03:52, 1 adar 2025 (UTC) == [[kerexne]] == @[[Bikarhêner:Rojhilat|Rojhilat]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:05, 1 adar 2025 (UTC) == [[pawan#p-mane|pawan]] == Ferhenga Hejar soranî ye, ji bo maneya "cihê qedexekirî, cihê inhisarî" ji xeynî wê çavkanî heye gelo —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:17, 3 adar 2025 (UTC) == [[taqane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 02:11, 6 adar 2025 (UTC) == [[gosirmetî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:07, 6 adar 2025 (UTC) == [[matîjêker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 14 adar 2025 (UTC) == [[hilewesan]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:14, 16 adar 2025 (UTC) == [[peydandin#p-mane|peydandin]] == Ji bo maneya [[dûre]], [[paşî]], [[piştî]] wê / wî ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:26, 19 adar 2025 (UTC) == [[peşar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:36, 19 adar 2025 (UTC) == [[nûzaf]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:30, 20 adar 2025 (UTC) == [[deynname]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 20 adar 2025 (UTC) == [[girtek]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:29, 20 adar 2025 (UTC) == [[bêşxane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:25, 23 adar 2025 (UTC) == [[superleheng]] == @[[Bikarhêner:Avestaboy|Avestaboy]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:34, 23 adar 2025 (UTC) == [[goranparêz]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:54, 27 adar 2025 (UTC) == [[raber#p-mane|raber]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:09, 1 nîsan 2025 (UTC) == [[morîvanî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:06, 1 nîsan 2025 (UTC) == [[wevde]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 12:17, 3 nîsan 2025 (UTC) == [[şandêr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:31, 3 nîsan 2025 (UTC) == [[giloverî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Tenê li ser Ferhenga Zaravên Teknîkî û hejmara yekem ya kovara Bernamegehê derbas dibe. —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:10, 4 nîsan 2025 (UTC) == [[xêvjimêr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 00:00, 12 nîsan 2025 (UTC) == [[paşekeft]] == @[[Bikarhêner:Jiyar Hesen|Jiyar Hesen]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:11, 13 nîsan 2025 (UTC) == [[paşekeft kirin]] == @[[Bikarhêner:Jiyar Hesen|Jiyar Hesen]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 11:12, 13 nîsan 2025 (UTC) == [[hawirkanî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:36, 20 nîsan 2025 (UTC) == [[hawirkan]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:18, 21 nîsan 2025 (UTC) : Di çavkanîyeke de "''hawrikan''" (ku wek forma vê kelîmeyê hatîye nîşandayîn û wek "hevrêyan" a kurmancî ye) bi maneya "''friends''"a îngilîzî hatîye emilandin. Wekî din ti çavkanî nîne ji bo vê peyvê. Ger ev "hevrik"a kurmancî be, li vir dîsa xelet e. Bi her awayî divê were jêbirin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:28, 21 nîsan 2025 (UTC) == [[hawirkanî]] == @[[Bikarhêner:Cyrus the virus|Cyrus the virus]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:18, 21 nîsan 2025 (UTC) == [[hawirkanvanî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:18, 21 nîsan 2025 (UTC) == [[riberiz]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:39, 21 nîsan 2025 (UTC) :Ez bawer im ku ev hat peyitandin. Min çavkanî di beşa gotûbêjê de dan û şablona bêçavkanîtiyê rakir. [[Bikarhêner:Ferhengvan|Ferhengvan]] ([[Gotûbêja bikarhêner:Ferhengvan|gotûbêj]]) 06:11, 25 nîsan 2025 (UTC) == [[awam]] == @[[User:Ferhengvan|Ferhengvan]] Min ev kelîme di ferhengên din de nedît. Gelo di kurmancî de tê bikaranîn? —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:09, 23 nîsan 2025 (UTC) :@[[Bikarhêner:Zerwanda|Zerwanda]] tu jî forma [[vam]] ya vê kelîmeyê diemilînî, gelo çavkanî ji bo wê jî heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:11, 23 nîsan 2025 (UTC) ::Min jî li vir peyda kir û dest kar anîn kir, hemin ev li guherrên dengî ên Kurmancî dihat (*ebam > *ewam > *wam > vam; wek *ebaj- > {{q|ku|vajî}}). Min gotibû qey di zarawayê kesekî da hebûye û wî bi ser va kiriye û jixwe nepêkan nîn e ku di zimên da hebe îcar rind e, nê min jî serkanî tine ji bonê. [[Bikarhêner:Zerwanda|Zerwanda]] ([[Gotûbêja bikarhêner:Zerwanda|gotûbêj]]) 21:37, 23 nîsan 2025 (UTC) :::https://bnk.institutkurde.org/images/pdf/4UVB2YMZG3.pdf :::Di vê kitêbê de bi forma wam derbas dibe 1 Wam : qerz, dên. " dîsa jî gereg 3 çavkanî hebe. :::Lê di beşa etîmolojiyê de eger em karibin zimanekî yekgirtî biemilînin, dê baştir be. Wekî din "bi vê enflasyona kelîmeyan" em nikarin ti tiştî bidin fêmkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:54, 23 nîsan 2025 (UTC) == [[arvanê hûr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:48, 27 nîsan 2025 (UTC) == [[damezrak]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:47, 27 nîsan 2025 (UTC) == [[mezrak]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 13:49, 27 nîsan 2025 (UTC) == [[hevhemetî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:25, 6 gulan 2025 (UTC) == [[navhemetî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:25, 6 gulan 2025 (UTC) == [[entîte]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:08, 17 gulan 2025 (UTC) == [[agirvekujêner]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:35, 21 gulan 2025 (UTC) == [[progres]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 23 gulan 2025 (UTC) == [[bûncî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 22:29, 28 gulan 2025 (UTC) == [[tasît]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:36, 31 gulan 2025 (UTC) == [[implîcît]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:37, 31 gulan 2025 (UTC) == [[hewedar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:14, 31 gulan 2025 (UTC) == [[destajo]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:38, 31 gulan 2025 (UTC) == [[binhimbank]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 01:23, 1 hezîran 2025 (UTC) == [[şîmane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:31, 2 hezîran 2025 (UTC) == [[materya]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:12, 5 hezîran 2025 (UTC) == [[bêtî]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:03, 7 hezîran 2025 (UTC) == [[rîbat]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:21, 9 hezîran 2025 (UTC) == [[hevtawan]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 10:26, 12 hezîran 2025 (UTC) :Pirsek: "Hevwate" kelîmeyên ku maneyan wan hev in. "hevtawan" çawa dibe "şirîkên sûcekê"? Gereg sûcên ku tiştê wan hev bin? Ew tişt çi ye? Çima dibe şirîk? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 10:32, 12 hezîran 2025 (UTC) ::Merheba! ::"Hevtawan" anku "şirîkên heman tawanê, kesên ku heman tawan kiriye/dikin", wek "hevkar = şirîkên heman karî, kesên ku heman karî dikin", "hevjîn = şirîkên heman jiyanê, kesên ku bi hev re dijîn"... [[Bikarhêner:Ferhengvan|Ferhengvan]] ([[Gotûbêja bikarhêner:Ferhengvan|gotûbêj]]) 06:11, 30 hezîran 2025 (UTC) == [[zanîş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 12:07, 14 hezîran 2025 (UTC) == [[zanîşwer]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 12:07, 14 hezîran 2025 (UTC) == [[zanmend]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 12:09, 14 hezîran 2025 (UTC) == [[zandar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:08, 14 hezîran 2025 (UTC) == [[zayîndar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:12, 14 hezîran 2025 (UTC) == [[zayindar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 21:12, 14 hezîran 2025 (UTC) == [[akund]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 01:16, 16 hezîran 2025 (UTC) == [[destbikar]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 07:41, 22 hezîran 2025 (UTC) == [[vekitandin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:DarkAngel2100|DarkAngel2100]] ([[Gotûbêja bikarhêner:DarkAngel2100|gotûbêj]]) 10:45, 2 tîrmeh 2025 (UTC) Çavkanî: Kurdish-English Dictionary by Baran Rizgar == [[peşarmend]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:54, 5 tîrmeh 2025 (UTC) == [[zaîd]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 06:59, 6 tîrmeh 2025 (UTC) == [[Xrîst]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 07:13, 10 tîrmeh 2025 (UTC) == [[hesibanî kirin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:48, 13 tîrmeh 2025 (UTC) == [[top danîn]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:08, 13 tîrmeh 2025 (UTC) == [[çûkger]] == @[[Bikarhêner:Dûrzan|Dûrzan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:49, 18 tîrmeh 2025 (UTC) == [[dûneçkar]] == @[[Bikarhêner:212.175.166.246|212.175.166.246]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:38, 10 tebax 2025 (UTC) == [[sermirov]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 15:22, 13 tebax 2025 (UTC) == [[nifira Esed]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 16:00, 19 tebax 2025 (UTC) == [[dilkrîz]] == @[[Bikarhêner:Kurd87612|Kurd87612]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:44, 23 tebax 2025 (UTC) == [[berxa Xwedê]] == @[[Bikarhêner:Kurd87612|Kurd87612]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:28, 31 tebax 2025 (UTC) == [[destmatî]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 17:47, 21 îlon 2025 (UTC) == [[sîbaq]] == @[[Bikarhêner:Ferhengvan|Ferhengvan]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 20:33, 27 îlon 2025 (UTC) == [[mirovê daristanê]] == @[[Bikarhêner:Hewarwîkîferheng|Hewarwîkîferheng]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 08:09, 18 çiriya pêşîn 2025 (UTC) == [[çavbijîşk]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 18:30, 24 çiriya pêşîn 2025 (UTC) == [[makeşar]] == @[[Bikarhêner:Avestaboy|Avestaboy]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 06:46, 14 kanûna pêşîn 2025 (UTC) :Silav @[[Bikarhêner:Bikarhêner|Bikarhêner]] min bi derew peyv çê nekir. Peyva makeşar di sepana O-ferheng û her wiha di ferhenga online ferhengkurdi.org ya '''Enstîtuya Kurdî ya Stenbolê''' tê xwendin. :https://ferhengkurdi.org/tr/kelime/make%C5%9Far-n [[Bikarhêner:Avestaboy|Avestaboy]] ([[Gotûbêja bikarhêner:Avestaboy|gotûbêj]]) 11:07, 18 kanûna pêşîn 2025 (UTC) ::Krîterên me yên tevlîkirina kelîmeyan heye. Ev made rîayeta wan krîteran nake. Lewma min vê kelîmeyê li vir bicih kir. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 23:28, 18 kanûna pêşîn 2025 (UTC) == [[bihîstinzanî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:30, 23 hezîran 2026 (UTC) == [[hevdilî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:28, 24 hezîran 2026 (UTC) == [[kemisandin]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:45, 24 hezîran 2026 (UTC) == [[kexme]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:53, 24 hezîran 2026 (UTC) == [[lêpirsyarker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:32, 24 hezîran 2026 (UTC) == [[raypirs]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:34, 24 hezîran 2026 (UTC) == [[helwestpirs]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:34, 24 hezîran 2026 (UTC) == [[kopirî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' xuyaye maneyeke wekî pir jî heye dikare were zêdekirin —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:33, 25 hezîran 2026 (UTC) == [[merxeme]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:55, 25 hezîran 2026 (UTC) == [[mohl]] == @[[Bikarhêner:Far ati|Far ati]] ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:14, 25 hezîran 2026 (UTC) == [[irfandarî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:30, 26 hezîran 2026 (UTC) == [[axulme]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:20, 30 hezîran 2026 (UTC) == [[şewane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:26, 1 tîrmeh 2026 (UTC) == [[poezî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:27, 1 tîrmeh 2026 (UTC) == [[sebaxker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:20, 1 tîrmeh 2026 (UTC) == [[sebaxfiroş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:21, 1 tîrmeh 2026 (UTC) == [[siboxfiroş]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:21, 1 tîrmeh 2026 (UTC) == [[diyardenasîtî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:26, 1 tîrmeh 2026 (UTC) == [[dawxane]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 10:41, 3 tîrmeh 2026 (UTC) == [[pêşajotî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:15, 3 tîrmeh 2026 (UTC) == [[kontînentaltirîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:35, 3 tîrmeh 2026 (UTC) == [[azmayîşker]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:16, 3 tîrmeh 2026 (UTC) == [[ateşparêz]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:19, 4 tîrmeh 2026 (UTC) == [[kurtetarîx]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:52, 4 tîrmeh 2026 (UTC) == [[besayetî]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:57, 4 tîrmeh 2026 (UTC) == [[tawbijêr]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:45, 4 tîrmeh 2026 (UTC) == [[destbir]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:30, 5 tîrmeh 2026 (UTC) == [[nekider]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:56, 5 tîrmeh 2026 (UTC) == [[niqar]] == —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:39, 5 tîrmeh 2026 (UTC) == [[parêzîn]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Ev form li ti derê peyda nabe. Berî çendîn salan hatîye çêkirin. Bi qenaeta min şaş e, lewma em jê bibin. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 10:29, 6 tîrmeh 2026 (UTC) == [[stêrfizîk]] == . —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:33, 6 tîrmeh 2026 (UTC) == [[pêçavik]] == . Eger ev kelîmeyeke mehelî be, Jkx şablona {{şx|dever|cihê ku lê tê bikaranîn}} li madeyê zêde bike. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:59, 7 tîrmeh 2026 (UTC) == [[qerqef]] == . Eger ev kelîmeyeke mehelî be, Jkx şablona {{şx|dever|cihê ku lê tê bikaranîn}} li madeyê zêde bike. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:17, 7 tîrmeh 2026 (UTC) == [[rakar]] == . Eger ev kelîmeyeke mehelî be, Jkx şablona {{şx|dever|cihê ku lê tê bikaranîn}} li madeyê zêde bike. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:30, 7 tîrmeh 2026 (UTC) == [[remilîn]] == . Eger ev kelîmeyeke mehelî be, Jkx şablona {{şx|dever|cihê ku lê tê bikaranîn}} li madeyê zêde bike. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:36, 7 tîrmeh 2026 (UTC) == [[segurî]] == . —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:51, 7 tîrmeh 2026 (UTC) == [[serdev]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:10, 7 tîrmeh 2026 (UTC) == [[serziman]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:01, 7 tîrmeh 2026 (UTC) == [[tenîsk]] == di Înternetê de gelek netîce derdikevin lê ji bo ku dûre ez kontrol bikim û çavkaniyên sehîh binivîsim li vir îlawe dikim. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:53, 7 tîrmeh 2026 (UTC) == [[tertî]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:58, 7 tîrmeh 2026 (UTC) == [[tirut]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:25, 7 tîrmeh 2026 (UTC) == [[tizqa]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:28, 7 tîrmeh 2026 (UTC) == [[têkilîdêr]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:31, 7 tîrmeh 2026 (UTC) == [[tîtalk]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:33, 7 tîrmeh 2026 (UTC) == [[vircoq]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:45, 7 tîrmeh 2026 (UTC) == [[xilêbat]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]]. Li gorî kurteya çêkirina sayfeyê li Qamişlo û Amûdê tê bikaranîn. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:14, 7 tîrmeh 2026 (UTC) == [[xin_û_cûc]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:27, 7 tîrmeh 2026 (UTC) == [[çiteba]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:38, 7 tîrmeh 2026 (UTC) == [[desttêl]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:45, 8 tîrmeh 2026 (UTC) == [[Mîmedol]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:51, 8 tîrmeh 2026 (UTC) == [[alaf]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:01, 8 tîrmeh 2026 (UTC) == [[aşirme]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 10:13, 10 tîrmeh 2026 (UTC) == [[geledîmentî]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:54, 13 tîrmeh 2026 (UTC) == [[çendîmentî]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:54, 13 tîrmeh 2026 (UTC) == [[paşmak]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:34, 15 tîrmeh 2026 (UTC) == [[rojeng]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:41, 18 tîrmeh 2026 (UTC) == [[bereyîşk]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:47, 19 tîrmeh 2026 (UTC) == [[wesekname]] == ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:08, 22 tîrmeh 2026 (UTC) == [[cemaetgeh]] == Bnr. [[Wîkîferheng:Pîvekên tevlîkirinê|Krîterên tevlîkirinê]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:17, 24 tîrmeh 2026 (UTC) em4ybpf0mtsjf5w2ck1o978za1t64at Gotûbêja MediaWiki:Newarticletext 9 845932 6291789 4766213 2026-07-28T02:25:06Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Li [[Wîkîferheng:Xebat/arşîv 1#MediaWiki:Newarticletext]] lînka nîqaşê ji [[Wîkîferheng:Xebat]] tê zêdekirin 6291789 wikitext text/x-wiki {{r|Balyozxane}} Ma "vegere" ne baştir e ji "bizîvire" bi vê maneyê? -- [[Bikarhêner:Guherto|Guherto]] ([[Gotûbêja bikarhêner:Guherto|gotûbêj]]) 20:24, 3 tebax 2020 (UTC) :{{r|Guherto}} Xebera te ye. Spas :) --[[Bikarhêner:Balyozxane|Balyozxane]] ([[Gotûbêja bikarhêner:Balyozxane|gotûbêj]]) 20:36, 3 tebax 2020 (UTC) == MediaWiki:Newarticletext == : ''Binêre [[Wîkîferheng:Xebat/arşîv 1#MediaWiki:Newarticletext]].''[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 02:25, 28 tîrmeh 2026 (UTC) 6lo5usd7f8f41qsypzhiao17329jcm7 Test 0 872455 6291684 6058180 2026-07-27T18:40:17Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291684 wikitext text/x-wiki {{bnr-h|test|têst|teşt}} == {{ziman|de}} == === Bilêvkirin === * {{deng|de|LL-Q188 (deu)-Sebastian Wallroth-Test.wav|Deng|dever=Berlîn, Almanya}} * {{deng|de|LL-Q188 (deu)-PeterTheOne-Test.wav|Deng|dever=Graz, Awistriya}} === Navdêr === {{navdêr|de|z=n}} # {{g|ku|îmtîhan}}, {{g|ku|azmûn}}, [[test]] l3762d185tbrrg9q0nk290h63sb5n53 Bikarhêner:Wikihez/newentrywiz.js 2 967094 6291739 6241300 2026-07-27T23:06:34Z Wikihez 7344 6291739 javascript text/javascript //Ji orîjînala [[en:User:Yair rand/newentrywiz.js]] // Hin beş ji [[ca:Usuari:Aleator/novaentrada.js]] û ji [[:en:User:So9q/new-entry-creator.js]] hatine wergirtin // {{belgekirin}} // todo: clean, jQuerize, use langmetadata, let users extend this /* jshint sub:true, shadow:true, undef:true, unused:true, strict:true, forin:true, latedef:true */ /* global jQuery */ // <nowiki> // Initialize variables // Support prefilling via GET function decapitalize(s) { if (typeof s !== 'string') return ''; return s.charAt(0).toLowerCase() + s.slice(1); } if (mw.util.getParamValue('ct') == 'true') { var necdata = { pos: decapitalize(mw.util.getParamValue('pos')), pos2: mw.util.getParamValue('pos'), }; var def2 = '[[' + mw.util.getParamValue('def') + ']]'; var neccode = mw.util.getParamValue('lang'); var transcription = mw.util.getParamValue('transcription'); var zayend = mw.util.getParamValue('zayend'); } else { neccode = typeof window.NEC_default_lang == "undefined" ? 'ku' : window.NEC_default_lang; var necdata = { pos: "navdêr", pos2: "Navdêr" }; } var necdefs = [ ['', [], [], [], [], [] ] ]; var necpost = []; //ji bo beşan for (var i = 4; i <= 16; ++i) { necpost[i] = []; } var necpostT = []; //ji bo şablonan for (var i = 0; i <= 9; ++i) { necpostT[i] = []; } var necpostlangtext = []; var title = mw.config.get('wgTitle'); var necinfls = { ku: { 'navdêr': ['{{', '}}', ['Zayend', '', [ ['Nayê zanîn', 'navdêr|ku|z=?'], ['tune', 'navdêr|ku|z=-'], ['nêr', 'ku-tewîn-nav|{{subst:PAGENAME}}|nêr}}\n{{navdêr|ku|z=n'], ['mê', 'ku-tewîn-nav|{{subst:PAGENAME}}|mê}}\n{{navdêr|ku|z=m'], ['mê û nêr', 'ku-tewîn-nav|{{subst:PAGENAME}}|mê û nêr}}\n{{navdêr|ku|z=mn'], ['bi gelemperî pirjimar', 'navdêr|ku|j=p+'], ]], ], 'rengdêr': ['{{', '}}', ['Qiyasbarî', '', [ ['qiyasbar', 'ku-tewîn-rd|{{subst:PAGENAME}}}}\n{{rengdêr|ku'], ['neqiyasbar', 'rengdêr|ku|form=-'] ]], ], 'lêker': ['{{lêker|ku', '}}', ['Cure', '', [ ['Navê zanîn', '|c=?'], ['gerguhêz', '|c=gh'], ['xwerû-gerguhêz', '|c=x-gh'], ['pêkhatî-gerguhêz', '|c=p-gh'], ['hevedudanî-gerguhêz', '|c=h-gh'], ['biwêjî-gerguhêz', '|c=b-gh'], ['negerguhêz', '|c=ngh'], ['xwerû-negerguhêz', '|c=x-ngh'], ['pêkhatî-negerguhêz', '|c=p-ngh'], ['hevedudanî-negerguhêz', '|c=h-ngh'], ['biwêjî-negerguhêz', '|c=b-ngh'] ]], ], 'hoker': ['{{hoker|ku', '}}' ], 'serenav': ['{{', '}}', ['Zayend', '', [ ['Nayê zanîn', 'serenav|ku|z=?'], ['tune', 'serenav|ku|z=-'], ['nêr', 'ku-tewîn-nav|{{subst:PAGENAME}}|nêr|y}}\n{{serenav|ku|z=n'], ['mê', 'ku-tewîn-nav|{{subst:PAGENAME}}|mê|y}}\n{{serenav|ku|z=m'], ]], ] }, ar: { 'navdêr': ['{{navdêr|ar', '}}', ['Cuda', '', [ ['tune', ''], ['input', ' ', '|'], ]], ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ['Zayend', '', [ ['Nayê zanîn', zayend ? "|z=" + zayend : '|z=' ], ['nêr', '|z=n'], ['mê', '|z=m'], ['mê û nêr', '|z=mn'], ['Bi gelemperî pirjimar', '|j=p+'], ]], ['Forma mê', '', [ ['tune', ''], ['input', ' ', '|m='], ]], ['Forma mê 2', '', [ ['tune', ''], ['input', ' ', '|m2='], ]], ['Forma mê 3', '', [ ['tune', ''], ['input', ' ', '|m3='], ]], ['Pirjimar', '', [ ['tune', ''], ['(nejimarbar)', '|j=nj'], ['input', ' ', '|p='] ]], ['Pirjimar 2', '', [ ['tune', ''], ['input', ' ', '|p2='], ]], ['Pirjimar 3', '', [ ['tune', ''], ['input', ' ', '|p3='], ]] ], 'rengdêr': ['{{rengdêr|ar', '}}', ['Cuda', '', [ ['tune', ''], ['input', ' ', '|'], ]], ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ['Zayend', '', [ ['Nayê zanîn', zayend ? "|z=" + zayend : '|z=' ], ['nêr', '|z=n'], ['mê', '|z=m'], ['mê û nêr', '|z=mn'], ]], ['Forma mê', '', [ ['tune', ''], ['input', ' ', '|m='], ]], ['Forma mê 2', '', [ ['tune', ''], ['input', ' ', '|m2='], ]], ['Forma mê 3', '', [ ['tune', ''], ['input', ' ', '|m3='], ]], ['Pirjimar', '', [ ['tune', ''], ['(nejimarbar)', '|j=nj'], ['input', ' ', '|p='] ]], ['Pirjimar 2', '', [ ['tune', ''], ['input', ' ', '|p2='], ]], ['Pirjimar 3', '', [ ['tune', ''], ['input', ' ', '|p3='], ]] ], 'reh': ['{{ar-reh', '}}', ], 'lêker': ['{{lêker|ar', '}}', ['Cuda', '', [ ['tune', ''], ['input', ' ', '|'], ]], ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ], 'hoker': ['{{hoker|ar', '}}', ['Cuda', '', [ ['tune', ''], ['input', ' ', '|'], ]], ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ], }, en: { 'navdêr': ['{{en-navdêr', '}}', ['Pirjimar', '', [ [title + 's', ''], [title + 'es', '|es'], ['(nejimarbar)', '|-'], ['input', 'Yên din: ', '|'] ]], ], 'lêker': ['{{en-lêker', '}}', ['Dema niha ya yekjimar ya kesa seyêm', '', [ [title + 's', '|' + title + 's'], ['input', 'Yên din: ', '|'] ]], ['Partîsîpa niha', '', [ [title + 'ing', '|' + title + 'ing'], ['input', 'Yên din: ', '|'] ]], ['Dema borî', '', [ [title + 'ed', '|' + title + 'ed'], ['input', 'Yên din: ', '|'] ]], ['Partîsîpa borî', '', [ [title + 'ed', '|' + title + 'ed'], ['input', 'Yên din: ', '|'] ]] ], 'rengdêr': ['{{', '}}', ['Komp û Sûperlatîv', '', [ ['nizanim', 'rengdêr|en'], ['more ' + title + ' most ' + title, 'en-rengdêr'], [title + 'er ' + title + 'est', 'en-rengdêr|er'], ['more ' + title + ' an ' + title + 'er', 'en-rengdêr|er|more'], ['(neqiyasbar)', '|-'], ]], ], 'hoker': ['{{hoker|en', '}}'], 'serenav': ['{{en-serenav', '}}', ['Pirjimar', '', [ ['Tune', ''], [title + 's', '|s'], ['input', 'Yên din: ', '|'] ]]], }, de: { 'navdêr': ['{{navdêr|de', '}}', ['Zayend', '', [ ['Nayê zanîn', zayend ? "|z=" + zayend : '|z=' ], ['nêr', '|z=n'], ['mê', '|z=m'], ['mê û nêr', '|z=mn'], ['Bi gelemperî pirjimar', '|j=p+'], ]], ['Pirjimar', '', [ ['tune', ''], ['(nejimarbar)', '|j=nj'], ['input', ' ', '|p='] ]] ], }, fa: { 'navdêr': ['{{navdêr|fa', '}}', ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ['Pirjimar', '', [ ['tune', ''], ['(nejimarbar)', '|j=nj'], ['input', ' ', '|p='] ]], ['Pirjimar 2', '', [ ['tune', ''], ['input', ' ', '|p2='], ]], ['Pirjimar 3', '', [ ['tune', ''], ['input', ' ', '|p3='], ]] ], 'rengdêr': ['{{rengdêr|fa', '}}', ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ], 'lêker': ['{{lêker|fa', '}}', ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ], 'hoker': ['{{hoker|fa', '}}', ['Translîterasyon', '', [ ['tune', transcription ? "|tr=" + transcription : '' ], ['input', ' ', '|tr='], ]], ], }, fr: { 'navdêr': ['{{navdêr|fr', '}}', ['Zayend', '', [ ['Nayê zanîn', zayend ? "|z=" + zayend : '|z=' ], ['nêr', '|z=n'], ['mê', '|z=m'], ['mê û nêr', '|z=mn'], ['Bi gelemperî pirjimar', '|j=p+'], ]], ['Pirjimar', '', [ ['tune', ''], [title + 's', '|p=' +title +'s'], ['(nejimarbar)', '|j=nj'], ['input', ' ', '|p='] ]] ], }, }; /* Notes: necfunction fills in the edit box necfunction2 creates the main menu stuff inside the span id'd necblah necfunction3 doesn't exist necfunction4 goes to necfunction5 (don't remember what this was for) necfunction5 creates the inflections options by filling in necinfls necfunction6 does some extra junk for the infl options input boxes necdefupdate makes the definitions/example sentence options necpostbox makes the extra junk ("More details") work (i think) More recent note: I knew next to nothing about javascript when I originally wrote this, so the code is an utter mess. It's also probably never going to be fixed up because really, I'd rather work on making WT:EDIT stuff the primary easy-editing method instead of tools like this. The necinfls object works like this: Each language is its own object, containing an object for each pos, which contains the information for that pos. The first part is the stuff that comes at the beginning of the template, the second is the stuff at the end, the third onward are the available parameters of the template and what stuff they produce. Each template parameter is an array, which contains the word that shows up at the beginning of the section, then a blank value, and then subarrays of each option. Each subarray contains the text that shows up in the editor, followed by the text that shows up in the textbox (the wikimarkup). Some onclick javascript can be added to an option as the third parameter in the array. If the option is an input box, the first parameter should be "input", followed by the editor text (DON'T leave this blank or the whole thing will blow up), followed by the pre-inputbox-value wikimarkup, followed by post-inputbox-value wikimarkup, followed by any extra js. Does this make any sense to anyone? :) Things to do: 1 Get quotations to work right 2 Fix up pronunciation section 3 Add little help thingies 4 Inflection tables 5 Get the example sentence auto-bolding to not stink 6 Build add-section stuff There are little href=javascript: things littered all over the place because I don't know any other way to make things look like unvisited links without having to actually put anything in the href. eh, sploot */ /* nyms 4 'Herwiha', 'Hevmane', 'Dijmane', 'Jêrnav', 'Jornav', 'Nêzîk', 9 derived 10 'Jê', 'Têkildar', 'Binêre herwiha', 12 etîmolojî 13 dûnde 14 bi zarava 15 werger 16 */ var necetym; var necpron; var necguharto; var necheadingorder = ['Bikaranîn', 'Bi alfabeyên din', 'Tewîn', 'Tewandin', 'Herwiha', 'Hevmane', 'Dijmane', 'Jêrnav', 'Jornav', 'Nêzîk', 'Jê', 'Têkildar', 'Binêre herwiha', 'Etîmolojî', 'Dûnde', 'Bi zaravayên din', 'Werger']; var necinputadvanced = ""; var necposlist = ['Navdêr', 'Lêker', 'Rengdêr', 'Hoker', 'Artîkel', 'Baneşan', 'Biwêj', 'Cînav', 'Daçek', 'Dordaçek', 'Girêdek', 'Gotineke pêşiyan', 'Hejmar', 'Hevok', 'Îfade', 'Kurtenav', 'Navgir', 'Paşgir', 'Paşdaçek', 'Pêşgir', 'Pirtik', 'Reh', 'Sembol', 'Serenav', 'Tîp']; var nectemplate = ['Hevdeng', 'IPA', 'Kîtekirin', 'Deng', 'Kategorî', 'Wîkîpediya', 'Bnr herwiha', 'Wêne', 'Ji', 'Qertaf']; function necfunction2() { /* CREATE OPTIONS */ var x = "Koda zimanî: <input type=text value='" + neccode + "' id='necinput' onKeyUp='neccode=this.value;necfunction();necfunction4();necfunction()' onblur=if (necCleanLangCode(this.value)){this.value=necCleanLangCode(this.value)};neccode=this.value;document.getElementById('nectransspan').style.display=((this.value=='" + neccode + "')?'':'none');if (/^[a-z]{2,3}(-[a-z\-]{1,7})?$/.test(this.value)){document.getElementById('neclangerror').style.display='none'}else{document.getElementById('neclangerror').style.display=''};necfunction();necfunction4();necfunction();necdefupdate() title='Koda zimanî binivîse, ku ji bo kurdî, en ji bo inglîzî'></input><span id=neclangerror style=display:none;color:red> ERROR: INVALID LANGUAGE CODE</span><br>Cureyê rêzimanê: "; for (i = 0; i < 4; ++i) { x += "<a id='necinputpos" + necposlist[i] + "' href=javascript: onclick=document.getElementById('necinputpos'+necdata.pos2).style.fontWeight='';necdata.pos2='" + necposlist[i] + "';necdata.pos='" + necposlist[i].toLowerCase() + "';this.style.fontWeight='bold';necfunction4();necfunction()"; if (!i) { x += " style='font-weight:bold'"; } x += ">" + necposlist[i] + "</a>, "; } x += "<span id='necinputpos'>Yên din: <input type=text onKeyUp=\"document.getElementById('necinputpos'+necdata.pos2).style.fontWeight='';necdata.pos2=this.value;necdata.pos=this.value.toLowerCase().replace(/ /g,'');this.parentNode.setAttribute('ID','necinputpos'+this.value);document.getElementById('necinputpos'+necdata.pos2).style.fontWeight='bold';necfunction();necfunction4()\" /><select onchange=\"document.getElementById('necinputpos'+necdata.pos2).style.fontWeight='';necdata.pos2=this.value;necdata.pos=this.value.toLowerCase().replace(/ /g,'');this.parentNode.setAttribute('ID','necinputpos'+this.value);document.getElementById('necinputpos'+necdata.pos2).style.fontWeight='bold';necfunction();necfunction4()\"><option value=''>Hilbijêre</option>"; for (i = 0; i < necposlist.length; ++i) { if (i > 3) { x += "<option>" + necposlist[i] + "</option>"; } } x += "</select></span><span id=necinfls></span><br>"; x += "<span id='necdefs'>Mane: <input type=text id='necinput3' onKeyUp=necdefs[0][0]=this.value;necfunction() /><br></span>Agahiyên din: <a href=javascript:necdefs.push(['',[],[],[],[],[]]);necdefupdate();necfunction() title='Maneyeke din binivîse'>Maneyeke din</a>, <a href=javascript: id=necetymbutton onclick=document.getElementById('necetymspan').style.display='';necetym=document.getElementById('necetyminput').value;necfunction();this.style.fontWeight='bold' title='Etîmolojî lê zêde bike'>Etîmolojî</a>, <a href=javascript: id=necpronbutton onclick=document.getElementById('necpronspan').style.display='';necpron=document.getElementById('necproninput').value;necfunction();this.style.fontWeight='bold' title='Bilêvkirinê lê zêde bike'>Bilêvkirin</a>, <a href=javascript: id=necguhartobutton onclick=document.getElementById('necguhartospan').style.display='';necguharto=document.getElementById('necguhartoinput').value;necfunction();this.style.fontWeight='bold' title='Şablona guharto lê zêde bike'>Guharto</a>. <span id='necetymspan' style='display:none'><br>Etîmolojî: <a href=javascript: onclick=necetym=undefined;document.getElementById('necetymspan').style.display='none';necfunction();document.getElementById('necetymbutton').style.fontWeight='' title='Etîmolojiyê jê bibe'>(Jê bibe)</a><br><textarea id=necetyminput onKeyUp=necetym=this.value;necfunction()></textarea></span><span id=necpronspan style='display:none'><br>Bilêvkirin: <a href=javascript: onclick=necpron=undefined;document.getElementById('necpronspan').style.display='none';necfunction();document.getElementById('necpronbutton').style.fontWeight='' title='Bilêvkirinê jê bibe'>(Jê bibe)</a><br><textarea id=necproninput onKeyUp=necpron=this.value;necfunction()></textarea></span><span id=necguhartospan style='display:none'><br>Guharto: <a href=javascript: onclick=necguharto=undefined;document.getElementById('necguhartospan').style.display='none';necfunction();document.getElementById('necguhartobutton').style.fontWeight='' title='Şablona guhartoyê jê bibe'>(Jê bibe)</a><br><textarea id=necguhartoinput onKeyUp=necguharto=this.value;necfunction()></textarea></span>"; x += "<br><span id=necpostboxT></span>Şablon: <select onchange=necpostboxT(this.value);this.selectedIndex=0;necfunction()><option select='selected'>Hilbijêre</option>"; for (i = 0; i < nectemplate.length; ++i) { x += "<option value=" + i + ">" + nectemplate[i] + "</option>"; } x += "</select>"; x += "<br>Beşên din: <span id=nectransspan> <a href=javascript: id=necSynonymsbutton onclick=necpost[5][necpost[5].length]=['',''];necpostbox();necfunction();this.style.fontWeight='bold' title='Hevmaneyên peyvê binivîse'>Hevmane</a>, <a href=javascript: id=necSynonymsbutton onclick=necpost[4][necpost[4].length]=['',''];necpostbox();necfunction();this.style.fontWeight='bold' title='Guhartoyên peyvê binivîse'>Herwiha</a>, <span id=nectransspan><a href=javascript: id=nectransbutton onclick=necpost[16][necpost[16].length]=['',''];necpostbox();necfunction();this.style.fontWeight='bold' title='Wergerekê lê zêde bike'>Werger</a>, </span>Yên din: <select onchange=necpostbox(this.value);this.selectedIndex=0;necfunction()><option select='selected'>Hilbijêre</option>"; for (i = 0; i < necheadingorder.length; ++i) { if (i != 4 && i != 5 && i != 16 && i != 13) { x += "<option value=" + i + ">" + necheadingorder[i] + "</option>"; } } x += "</select><br><span id=necpostbox></span><div style='float:right;'><a href=/w/index.php?title=User_talk:Wikihez/newentrywiz.js&action=edit&section=new title='Pirsgirêkan nîşan bide'>Pirsgirêk?</a></div>"; document.getElementById("editform").insertBefore(document.getElementById("necblah"), document.getElementById("editform").firstChild); document.getElementById("necblah").innerHTML = x; if (document.URL.match("&section=new")) { document.getElementById("wpSummaryLabel").parentNode.removeChild(document.getElementById("wpSummaryLabel")); document.getElementById("wpSummary").parentNode.removeChild(document.getElementById("wpSummary")); } } // Fill in the edit box. function necfunction() { var k = ""; if (document.URL.match("&section=new")) { k += "\n{{şêwexirab|sedem=Bi [[WF:NEC]] zimanekî din lê hatiye zêdekirin, heke rêzê zimanî ya alfabetîk rast be vê şablonê rakin.}}\n\n"; } else { var neceditsummary = "([[Bikarhêner:Wikihez/newentrywiz.js|NEC]]) +" + neccode + ":" + necdata.pos + ": "; //edit summary if (necguharto != undefined) { neceditsummary += "Guhartoyeke [[" + necguharto + "]]"; } if (def2 != undefined) { neceditsummary += "Bi [[Bikarhêner:Wikihez/CreateTranslation.js|amûrê]] ji tercimeyên " + def2 + ": "; if (transcription != "") { neceditsummary += 'tr=' + transcription; } if (zayend != "") { neceditsummary += "|z=" + zayend + " "; } } for (i = 0; i < necdefs.length; ++i) { neceditsummary += ((i != 0) ? ', ' : '') + necdefs[i][0]; } document.getElementById("wpSummary").value = neceditsummary; } if (necpostT[6][0] != undefined) { k += "{{binêre herwiha"; for (i = 0; i < necpostT[6].length; i++) { k += "|" + necpostT[6][i]; } k += "}}\n\n"; } k += "== {{ziman|" + document.getElementById('necinput').value + "}} =="; k += "\n"; if (necpron != undefined || necpostT[0][0] != undefined || necpostT[3][0] != undefined || necpostT[2][0] != undefined || necpostT[1][0] != undefined) { k += "\n=== Bilêvkirin ===\n"; if (necpron != undefined) { k += necpron + "\n"; } if (necpostT[1][0] != undefined) { for (i = 0; i < necpostT[1].length; ++i) { if (necpostT[1][i][0]) { k += "* {{IPA|" + neccode + "|" + necpostT[1][i]; }else{ k += "* {{" + neccode + "-IPA"; } k += "}}\n"; } } if (necpostT[3][0] != undefined) { for (i = 0; i < necpostT[3].length; ++i) { k += "* {{deng|" + neccode + "|" + necpostT[3][i][0] + "|Deng"; if (necpostT[3][i][1]) { k += " (" + necpostT[3][i][1] + ")"; } k += "}}\n"; } } if (necpostT[2][0] != undefined) { if (necpostT[2][i]){ k += "* {{kîte"; for (i = 0; i < necpostT[2].length; i++) { k += "|" + necpostT[2][i]; } }else { k += "* {{" + neccode + "-kîte"; } k += "}}\n"; } if (necpostT[0][0] != undefined) { k += "* {" + "{hevdeng|" + neccode; for (i = 0; i < necpostT[0].length; i++) { k += "|" + necpostT[0][i]; } k += "}}\n"; } } k += "\n=== " + necdata.pos2 + " ===\n"; if (necpostT[7][0] != undefined) { for (i = 0; i < necpostT[7].length; ++i) { k += "[[Wêne:" + necpostT[7][i][0] + "|thumb|"; if (necpostT[7][i][1]) { k += necpostT[7][i][1]; }else { k + "'''" + title + "'''"; } k += "]]\n"; } } if (necpostT[5][0] != undefined) { for (i = 0; i < necpostT[5].length; ++i) { k += "{{Wîkîpediya"; if (neccode != 'ku') { k += "|ziman=" + neccode; } if (necpostT[5][i][0]) { k += "|" + necpostT[5][i][0]; if (necpostT[5][i][1]) { k += "|" + necpostT[5][i][1]; } } k += "}}\n"; } } if (!neccode) { neccode = ''; } if (neccode != '' && necinfls[neccode] && necinfls[neccode][necdata.pos] && necinfls[neccode][necdata.pos][2]) { if (necdata[neccode + "-" + necdata.pos + "2"] != "Advanced") { if (necinfls[neccode][necdata.pos][0] != undefined) { k += necinfls[neccode][necdata.pos][0]; } var x = necinfls[neccode][necdata.pos]; for (var z = 0; z < x.length; ++z) { if (z <= 1) { continue; } var zz = neccode + "-" + necdata.pos + z; for (var y = 0; y < x[z][2].length; ++y) // search for inflections { if (x[z][2][y][0] != "input" && necdata[zz] == x[z][2][y][0]) // is selected option, not input box { k += x[z][2][y][1]; break; } if (x[z][2][y][0] == "input" && necfunction7(x[z][2], necdata[zz]) == false) { k += x[z][2][y][2] + necdata[zz]; } } } if (necinfls[neccode][necdata.pos][1] != undefined) { k += necinfls[neccode][necdata.pos][1]; } } else { k += necinputadvanced; } } else { if (necinputadvanced) { k += necinputadvanced; } else { if (neccode != '' && necinfls[neccode] && necinfls[neccode][necdata.pos]) { k += necinfls[neccode][necdata.pos][0]; k += necinfls[neccode][necdata.pos][1]; } else { k += '{{' + necdata.pos2.toLowerCase() + '|' + neccode; if (def2 != undefined) { if (transcription != "") { k += '|tr=' + transcription; } if (zayend != "") { k += "|z=" + zayend; } }else { if ((new LangMetadata()).guessScript(neccode) != 'Latn'){ k += "|tr="; } } k += '}}'; } } } k += ""; if (necguharto != undefined) { for (i = 0; i < necdefs.length && i <1; ++i) { k += "\n# "; // etîket ji bo guhartoyê if (necdefs[i][4].length > 0) { k += "{{f|" + neccode; for (e = 0; e < necdefs[i][4].length; ++e) { k += "|" + necdefs[i][4][e]; } k += "}} "; } k += "{{guharto|" + neccode + "|" + necguharto; if (necdefs[i][0]) { k += "|w=" + necdefs[i][0]; } k += '}}'; } } if (def2 != undefined) { for (i = 0; i < necdefs.length && i <1; ++i) { k += '\n# '; // etîket ji bo wergeran if (necdefs[i][4].length > 0) { k += "{{f|" + neccode; for (e = 0; e < necdefs[i][4].length; ++e) { k += "|" + necdefs[i][4][e]; } k += "}} "; } k +=def2; if (necdefs[i][0]) { k += ' {{mane|' + necdefs[i][0] + '}}'; } // hevmane ji bo wergeran if (necdefs[i][3].length > 0) { k += "\n#: {{hevmaneyên peyvê|" + neccode; for (e = 0; e < necdefs[i][3].length; ++e) { k += "|" + necdefs[i][3][e]; } k += "}} "; } // dijmane ji bo wergeran if (necdefs[i][5].length > 0) { k += "\n#: {{dijmaneyên peyvê|" + neccode; for (e = 0; e < necdefs[i][5].length; ++e) { k += "|" + necdefs[i][5][e]; } k += "}} "; } //mînak ji bo wergeran for (var l = 0; l < necdefs[i][1].length; ++l) { if (neccode == "ku") { k += "\n#: {{mk|ku|" + necdefs[i][1][l][0].replace(new RegExp("(" + title + "([^( |,|;|\?|\.|\!)]+)?)", "ig"), "'''$1'''") + ""; }else { k += "\n#: {{mk|" + neccode + "|" + necdefs[i][1][l][0].replace(new RegExp("(" + title + "([^( |,|;|\?|\.|\!)]+)?)", "ig"), "'''$1'''") + "''"; } if (neccode != "ku" && (new LangMetadata()).guessScript(neccode) != 'Latn') { k += "|tr=" + necdefs[i][1][l][1] + ""; //transliterasyon k += "|w=" + necdefs[i][1][l][2] + ""; }else if (neccode != "ku") { k += "|w=" + necdefs[i][1][l][2] + ""; } k += "}}"; } //jêgirtin ji bo wergeran for (l = 0; l < necdefs[i][2].length; ++l) { k += "\n#* {{jêder-"; // navê şablonê binivîse malper/kitêb/kovar? if (necdefs[i][2][l][0]) { k += necdefs[i][2][l][0]; }else { k += "kitêb"; } k += "|" + neccode + "|jêgirtin="; k += necdefs[i][2][l][8].replace(new RegExp("(" + title + "([^( |,|;|\?|\.|\!)]+)?)", "ig"), "'''$1'''"); if (necdefs[i][2][l][1]) { k += "|nivîskar=" + necdefs[i][2][l][1]; } if (necdefs[i][2][l][2]) { k += "|sernav=" + necdefs[i][2][l][2]; } if (necdefs[i][2][l][3]) { k += "|weşanxane=" + necdefs[i][2][l][3]; } if (necdefs[i][2][l][5]) { if (necdefs[i][2][l][0] == 'kovar') { k += "|hejmar=" + necdefs[i][2][l][5]; }else if (necdefs[i][2][l][0] == 'kitêb') { k += "|ISBN=" + necdefs[i][2][l][5]; }else { k += "|malper=" + necdefs[i][2][l][5]; } } if (necdefs[i][2][l][6]) { k += "|url=" + necdefs[i][2][l][6]; } if (necdefs[i][2][l][7]) { k += "|sal=" + necdefs[i][2][l][7]; } if (necdefs[i][2][l][4]) { k += "|rûpel=" + necdefs[i][2][l][4] + "}}"; } else k += "}}"; if (neccode != "ku") { k += "\n#*: " + necdefs[i][2][l][9]; } } } } if (def2 != undefined || necguharto != undefined) { i = 1; }else { i = 0; } for (i; i < necdefs.length; ++i) { k += "\n# "; // etîket if (necdefs[i][4].length > 0) { k += "{{f|" + neccode; for (e = 0; e < necdefs[i][4].length; ++e) { k += "|" + necdefs[i][4][e]; } k += "}} "; } k += necdefs[i][0]; // hevmane if (necdefs[i][3].length > 0) { k += "\n#: {{hevmane|" + neccode; for (e = 0; e < necdefs[i][3].length; ++e) { k += "|" + necdefs[i][3][e]; } k += "}} "; } // dijmane if (necdefs[i][5].length > 0) { k += "\n#: {{dijmane|" + neccode; for (e = 0; e < necdefs[i][5].length; ++e) { k += "|" + necdefs[i][5][e]; } k += "}} "; } for (var l = 0; l < necdefs[i][1].length; ++l) { if (neccode == "ku") { k += "\n#: {{mk|ku|" + necdefs[i][1][l][0].replace(new RegExp("(" + title + "([^( |,|;|\?|\.|\!)]+)?)", "ig"), "'''$1'''") + ""; }else { k += "\n#: {{mk|" + neccode + "|" + necdefs[i][1][l][0].replace(new RegExp("(" + title + "([^( |,|;|\?|\.|\!)]+)?)", "ig"), "'''$1'''"); } if (neccode != "ku" && (new LangMetadata()).guessScript(neccode) != 'Latn') { k += "|tr=" + necdefs[i][1][l][1] + ""; //transliterasyon k += "|w=" + necdefs[i][1][l][2] + ""; }else if (neccode != "ku") { k += "|w=" + necdefs[i][1][l][2] + ""; } k += "}}"; } for (l = 0; l < necdefs[i][2].length; ++l) { k += "\n#* {{jêder"; // navê şablonê binivîse malper/kitêb/kovar? if (necdefs[i][2][l][0]) { if (necdefs[i][2][l][0] == 'kitêb' || necdefs[i][2][l][0] == 'kovar' || necdefs[i][2][l][0] == 'malper'){ k += '-' + necdefs[i][2][l][0]; }else{ k += '|' + necdefs[i][2][l][0]; } }else { k += "-kitêb"; } k += "|" + neccode + "|jêgirtin="; k += necdefs[i][2][l][8].replace(new RegExp("(" + title + "([^( |,|;|\?|\.|\!)]+)?)", "ig"), "'''$1'''"); if (necdefs[i][2][l][1]) { k += "|nivîskar=" + necdefs[i][2][l][1]; } if (necdefs[i][2][l][2]) { k += "|sernav=" + necdefs[i][2][l][2]; } if (necdefs[i][2][l][3]) { k += "|weşanxane=" + necdefs[i][2][l][3]; } if (necdefs[i][2][l][5]) { if (necdefs[i][2][l][0] == 'kovar') { k += "|hejmar=" + necdefs[i][2][l][5]; }else if (necdefs[i][2][l][0] == 'kitêb') { k += "|ISBN=" + necdefs[i][2][l][5]; }else { k += "|malper=" + necdefs[i][2][l][5]; } } if (necdefs[i][2][l][6]) { k += "|url=" + necdefs[i][2][l][6]; } if (necdefs[i][2][l][7]) { k += "|sal=" + necdefs[i][2][l][7]; } if (necdefs[i][2][l][4]) { k += "|rûpel=" + necdefs[i][2][l][4] + "}}"; } else k += "}}"; if (neccode != "ku") { k += "\n#*: " + necdefs[i][2][l][9]; } } } /* SUBHEADERS */ for (var o = 0; o <= 3; ++o) { if (necpost[o] != undefined) { k += "\n\n==== " + necheadingorder[o] + " ====\n" + necpost[o]; } } for (o = 4; o <= 6; ++o) { if (necpost[o][0] != undefined) { k += "\n\n==== " + necheadingorder[o] + " ===="; } for (i = 0; i < necpost[o].length; ++i) { k += "\n* {{mane|" + necpost[o][i][0] + "}} "; for (var u = 0; u < necpost[o][i].length; ++u) { if (u != 0) { if (u != 1) { k += ", "; } k += "{{g|" + neccode + "|" + necpost[o][i][u] + "}}"; } } } } for (o = 7; o <= 12; ++o) { if (necpost[o][0] != undefined) { k += "\n\n==== " + necheadingorder[o] + " ===="; } for (i = 0; i < necpost[o].length; ++i) { k += "\n* {{g|" + neccode + "|" + necpost[o][i] + "}}"; } } if (necetym != undefined || necpostT[8][0] != undefined|| necpostT[9][0] != undefined) { k += "\n\n==== Etîmolojî ====\n"; }else { if (neccode == "ku" && necguharto == undefined) k += "\n\n==== Etîmolojî ====\n{{bêetîmolojî}}"; } if (necpostT[8][0] != undefined || necpostT[9][0] != undefined) { k += "Ji "; } for (i = 0; i < necpostT[8].length; ++i) { k += "{{"; if (necpostT[8][i][0]){ k += necpostT[8][i][0] + '|'; }else { k += "ji|"; } k += necpostT[8][i][1] + '|' + neccode; k += "|" + necpostT[8][i][2]; if (necpostT[8][i][3]) { k += "|w=" + necpostT[8][i][3]; } if (necpostT[8][i][4]) { k += "|tr=" + necpostT[8][i][4]; } k += "}}"; if (necpostT[8].length > 1 ) { k += ", ji "; } } if (necpostT[8][0] != undefined && necpostT[9][0] != undefined) { k += " wekheva "; }else if (necpostT[8][0] == undefined || necpostT[9][0] == undefined) { k += ""; } for (i = 0; i < necpostT[9].length; ++i) { k += "{{qertaf|" + neccode; k += "|" + necpostT[9][i][0]; k += "|" + necpostT[9][i][1]; if (necpostT[9][i][2]) { k += "|w1=" + necpostT[9][i][2]; } if (necpostT[9][i][3]) { k += "|w2=" + necpostT[9][i][3]; } if (necpostT[9][i][4]) { k += "|tr1=" + necpostT[9][i][4]; } if (necpostT[9][i][5]) { k += "|tr2=" + necpostT[9][i][5]; } k += "}}"; } if (necetym != undefined) { k += necetym; } var HH=0;//hi ha? for (o = 14; o <= 16; ++o) { if (necpost[o][0] != undefined) { k += "\n\n==== " + necheadingorder[o] + " ===="; } if (o == 14) { for (i = 0; i < necpost[14].length; ++i) { k += "\n* {{dû|" + necpost[14][i][0]; k += "|" + necpost[14][i][1] + "}}"; } }else if (o == 15) { if (necpost[15] != undefined) { for (i = 0; i < necpost[15].length; ++i) { k += "\n* {{Z|" + necpost[15][i][0] + "}}: "; for (var uu in necpost[15][i]) { if (uu != 0) { //concatenar trads if (uu != 1) { k += ", "; } k += "{{W-|" + necpost[15][i][0] + "|" + necpost[15][i][uu] + "}}"; } } } } }else if (o == 16) { HH = 0; if (neccode == "ku" && necguharto == undefined && necpost[16].length < 1){ k += "\n\n==== Werger ====\n{{werger-ser}}\n{{werger-bin}}"; } for (i = 0; i < necpost[16].length; ++i) { if (HH == 0) { k += "\n{{werger-ser}}"; } k += "\n* {{Z|" + necpost[16][i][0] + "}}: "; for (var uu in necpost[16][i]) { if (uu != 0) { //concatenar trads if (uu != 1) { k += ", "; } k += "{{W|" + necpost[16][i][0] + "|" + necpost[16][i][uu] + "}}"; } } if (HH == 0) { k += "" + ""; HH = 1; } } if (HH == 1) { k += "\n{{werger-bin}}\n"; } } } if (necpostT[4][0] != undefined) { k += "\n\n{{mijar|" + neccode; for (i = 0; i < necpostT[4].length; i++) { k += "|" + necpostT[4][i]; } k += "}}"; } $(document.editform.wpTextbox1).val(k); } function necCleanLangCode(lang) // taken from wt:edit { var key = lang.toLowerCase().replace(' ', ''); var dict = { aar: "aa", afar: "aa", abk: "ab", abkhazian: "ab", afr: "af", afrikaans: "af", aka: "ak", akan: "ak", amh: "am", amharic: "am", ara: "ar", arabic: "ar", arg: "an", aragonese: "an", asm: "as", assamese: "as", ava: "av", avaric: "av", ave: "ae", avestan: "ae", aym: "ay", aymara: "ay", aze: "az", azerbaijani: "az", bak: "ba", bashkir: "ba", bam: "bm", bambara: "bm", bel: "be", belarusian: "be", ben: "bn", bengali: "bn", bis: "bi", bislama: "bi", bod: "bo", tibetan: "bo", bos: "bs", bosnian: "bs", bre: "br", breton: "br", bul: "bg", bulgarian: "bg", cat: "ca", catalan: "ca", ces: "cs", czech: "cs", cha: "ch", chamorro: "ch", che: "ce", chechen: "ce", chu: "cu", churchslavic: "cu", chv: "cv", chuvash: "cv", cor: "kw", cornish: "kw", cos: "co", corsican: "co", cre: "cr", cree: "cr", cym: "cy", welsh: "cy", dan: "da", danish: "da", deu: "de", german: "de", div: "dv", dhivehi: "dv", dzo: "dz", dzongkha: "dz", ell: "el", greek: "el", eng: "en", english: "en", epo: "eo", esperanto: "eo", est: "et", estonian: "et", eus: "eu", basque: "eu", ewe: "ee", fao: "fo", faroese: "fo", fas: "fa", persian: "fa", fij: "fj", fijian: "fj", fin: "fi", finnish: "fi", fra: "fr", french: "fr", fry: "fy", westernfrisian: "fy", ful: "ff", fulah: "ff", gla: "gd", scottishgaelic: "gd", gle: "ga", irish: "ga", glg: "gl", galician: "gl", glv: "gv", manx: "gv", grn: "gn", guarani: "gn", guj: "gu", gujarati: "gu", hat: "ht", haitian: "ht", hau: "ha", hausa: "ha", heb: "he", hebrew: "he", her: "hz", herero: "hz", hin: "hi", hindi: "hi", hmo: "ho", hirimotu: "ho", hrv: "hr", croatian: "hr", hun: "hu", hungarian: "hu", hye: "hy", armenian: "hy", ibo: "ig", igbo: "ig", ido: "io", iii: "ii", sichuanyi: "ii", iku: "iu", inuktitut: "iu", ile: "ie", interlingue: "ie", ina: "ia", interlingua: "ia", ind: "id", indonesian: "id", ipk: "ik", inupiaq: "ik", isl: "is", icelandic: "is", ita: "it", italian: "it", jav: "jv", javanese: "jv", jpn: "ja", japanese: "ja", kal: "kl", kalaallisut: "kl", kan: "kn", kannada: "kn", kas: "ks", kashmiri: "ks", kat: "ka", georgian: "ka", kau: "kr", kanuri: "kr", kaz: "kk", kazakh: "kk", khm: "km", centralkhmer: "km", kik: "ki", kikuyu: "ki", kin: "rw", kinyarwanda: "rw", kir: "ky", kirghiz: "ky", kom: "kv", komi: "kv", kon: "kg", kongo: "kg", kor: "ko", korean: "ko", kua: "kj", kuanyama: "kj", kur: "ku", kurdish: "ku", lao: "lo", lat: "la", latin: "la", lav: "lv", latvian: "lv", lim: "li", limburgan: "li", lin: "ln", lingala: "ln", lit: "lt", lithuanian: "lt", ltz: "lb", luxembourgish: "lb", lub: "lu", lubakatanga: "lu", lug: "lg", ganda: "lg", mah: "mh", marshallese: "mh", mal: "ml", malayalam: "ml", mar: "mr", marathi: "mr", mkd: "mk", macedonian: "mk", mlg: "mg", malagasy: "mg", mlt: "mt", maltese: "mt", mon: "mn", mongolian: "mn", mri: "mi", maori: "mi", msa: "ms", malay: "ms", mya: "my", burmese: "my", nau: "na", nauru: "na", nav: "nv", navajo: "nv", nbl: "nr", southndebele: "nr", nde: "nd", northndebele: "nd", ndo: "ng", ndonga: "ng", nep: "ne", nepali: "ne", nld: "nl", dutch: "nl", nno: "nn", norwegiannynorsk: "nn", nob: "nb", norwegianbokmal: "nb", nor: "no", norwegian: "no", nya: "ny", nyanja: "ny", oci: "oc", occitan: "oc", oji: "oj", ojibwa: "oj", ori: "or", oriya: "or", orm: "om", oromo: "om", oss: "os", ossetian: "os", pan: "pa", panjabi: "pa", pli: "pi", pali: "pi", pol: "pl", polish: "pl", por: "pt", portuguese: "pt", pus: "ps", pushto: "ps", que: "qu", quechua: "qu", roh: "rm", romansh: "rm", ron: "ro", romanian: "ro", run: "rn", rundi: "rn", rus: "ru", russian: "ru", sag: "sg", sango: "sg", san: "sa", sanskrit: "sa", sin: "si", sinhala: "si", slk: "sk", slovak: "sk", slv: "sl", slovenian: "sl", sme: "se", northernsami: "se", smo: "sm", samoan: "sm", sna: "sn", shona: "sn", snd: "sd", sindhi: "sd", som: "so", somali: "so", sot: "st", southernsotho: "st", spa: "es", spanish: "es", sqi: "sq", albanian: "sq", srd: "sc", sardinian: "sc", srp: "sr", serbian: "sr", ssw: "ss", swati: "ss", sun: "su", sundanese: "su", swa: "sw", swahili: "sw", swe: "sv", swedish: "sv", tah: "ty", tahitian: "ty", tam: "ta", tamil: "ta", tat: "tt", tatar: "tt", tel: "te", telugu: "te", tgk: "tg", tajik: "tg", tgl: "tl", tagalog: "tl", tha: "th", thai: "th", tir: "ti", tigrinya: "ti", ton: "to", tonga: "to", tsn: "tn", tswana: "tn", tso: "ts", tsonga: "ts", tuk: "tk", turkmen: "tk", tur: "tr", turkish: "tr", twi: "tw", uig: "ug", uighur: "ug", ukr: "uk", ukrainian: "uk", urd: "ur", urdu: "ur", uzb: "uz", uzbek: "uz", ven: "ve", venda: "ve", vie: "vi", vietnamese: "vi", vol: "vo", volapuk: "vo", wln: "wa", walloon: "wa", wol: "wo", wolof: "wo", xho: "xh", xhosa: "xh", yid: "yi", yiddish: "yi", yor: "yo", yoruba: "yo", zha: "za", zhuang: "za", zho: "zh", chinese: "zh", zul: "zu", zulu: "zu" }; return dict[key]; } function necfunction4() { if (!neccode) { neccode = ''; } if (neccode && necinfls[neccode] && necinfls[neccode][necdata.pos] != undefined && necinfls[neccode][necdata.pos][2] != undefined) { necfunction5(necinfls[neccode][necdata.pos]); } else { var qq = neccode + "-" + necdata.pos + '2'; var xx = "<span class=msgfornonnewbies "; if (necinputadvanced) { xx += "style='font-weight:bold' "; } xx += "><br>Bi koda wîkiyê binivîse: <input type=text value='" + necinputadvanced + "' onKeyUp=\"necinputadvanced=this.value;if (this.value){this.parentNode.style.fontWeight='bold'}else{this.parentNode.style.fontWeight=''};necfunction()\" /></span>"; document.getElementById("necinfls").innerHTML = xx; necfunction(); } } function necfunction5(a) { /* INFLECTION OPTIONS */ var q = ""; for (var r = 0; r < a.length; ++r) { if (r <= 1) { continue; } var qq = neccode + "-" + necdata.pos + r; if (necdata[qq] == undefined) { if (a[r][2][0][0] == 'input') { necdata[qq] = ''; } else { necdata[qq] = a[r][2][0][0]; } } q += "<br>" + a[r][0] + ": "; for (i = 0; i < a[r][2].length; ++i) { if (a[r][2][i][0] != 'input') { q += "<a href=javascript: id='necinput" + qq + a[r][2][i][0] + "' onclick=\""; if (a[r][2][i][2]) { q += a[r][2][i][2] + ";"; } q += "necdata[\'" + qq + "\']=\'" + a[r][2][i][0] + "\';necfunction4();necfunction()\">" + a[r][2][i][0] + "</a>"; if (i != a[r][2].length - 1) { q += ", "; } } else { q += "<span id='necinput" + qq; if (necdata[qq] != "Advanced" && necfunction7(a[r][2], necdata[qq]) == false) { q += necdata[qq]; } q += "'>" + a[r][2][i][1] + "<input type=text value='' id='"; q += neccode + "-" + necdata.pos + "-" + r + "-" + i; q += "' onKeyUp="; if (a[r][2][i][4]) { q += a[r][2][i][4] + ";"; } q += "necfunction6('" + qq + "','" + neccode + "-" + necdata.pos + "-" + r + "-" + i + "');"; q += "necfunction() /></span>"; if (i != a[r][2].length - 1) { q += ", "; } } } /* ADVANCED OPTIONS */ if (r == 2) { q += "<br><span id='necinput" + qq + "Advanced' class=msgfornonnewbies><span style=font-weight:normal></span>Bi koda wîkiyê binivîse: <input type=text value='" + necinputadvanced + "' onKeyUp=necinputadvanced=this.value;document.getElementById('necinput" + qq + "'+necdata['" + qq + "']).style.fontWeight='';necdata['" + qq + "']='Advanced';document.getElementById('necinput" + qq + "'+necdata['" + qq + "']).style.fontWeight='bold';necfunction() /></span>"; } } document.getElementById("necinfls").innerHTML = q; for (var r = 0; r < a.length; ++r) { if (r <= 1) { continue; } var qq = neccode + "-" + necdata.pos + r; document.getElementById('necinput' + qq + necdata[qq]).style.fontWeight = 'bold'; if (document.getElementById('necinput' + qq + necdata[qq]).childNodes[1] && necdata[qq] != 'Advanced' && necfunction7(a[r][2], necdata[qq]) == false) { document.getElementById('necinput' + qq + necdata[qq]).childNodes[1].value = necdata[qq]; } } } function necdefupdate() { /* DEFINITIONS */ var def = "<input class='unselectable' type='button' name='PasteOver' value='[[ + ]]' onmousedown='wikilinkText(); return false'><input class='unselectable' type='button' name='PasteOver' value='|' onmousedown='wikiPipe(); return false'><input class='unselectable' type='button' name='PasteOver' value='{{ + }}' onmousedown='wikiText(); return false'><br>"; for (i = 0; i < necdefs.length; i++) { def += "Mane: <input size=70 type=text value='" + necdefs[i][0] + "' onKeyUp=necdefs[" + i + "][0]=this.value;necfunction() />"; if (i > 0) { def += "<a href=javascript:necdefs.splice(" + i + ",1);uNec() title='Maneyê jê bibe'> (–)</a>"; } def += "<br><span style='padding-left:40px;'></span><a href=javascript:necdefs[" + i + "][1].push(['','','']);uNec() title='Mînakekê lê zêde bike'> (+mînak)</a><a href=javascript:necdefs[" + i + "][2].push(['','','','','','','','','','']);uNec() title='Jêgirtinekê lê zêde bike'> (+jêgirtin)</a><a href=javascript:necdefs[" + i + "][3].push(['']);uNec();document.getElementById('necinputH" + i + "').focus() title='Hevmane lê zêde bike'> (+hevmane)</a><a href=javascript:necdefs[" + i + "][5].push(['']);uNec();document.getElementById('necinputD" + i + "').focus() title='Dijmane lê zêde bike'> (+dijmane)</a><a href=javascript:necdefs[" + i + "][4].push(['']);uNec();document.getElementById('necinputE" + i + "').focus() title='Etîketek lê zêde bike'> (+etîket)</a>"; if (necdefs[i][3].length > 0){//hevmane def += "<br><span style='padding-left:50px;'>Hevmane: </span>"; for (l = 0; l < necdefs[i][3].length; l++) { def += "<input type=text id='necinputH"+ l +"' size=10 value='" + necdefs[i][3][l][0] + "' onKeyUp=necdefs[" + i + "][3][" + l + "][0]=this.value;necfunction() />"; if (necdefs[i][3].length > 1){ def += ", "; } } def += "<a href=javascript:necdefs[" + i + "][3].push(['']);uNec();document.getElementById('necinputH" + l + "').focus() title='Hevmaneyekê lê zêde bike'> (+)</a>"; def += "<a href=javascript:necdefs[" + i + "][3].splice(" + (necdefs[i][3].length - 1) + ",1);uNec() title='Hevmaneyê jê bibe'> (–)</a>"; } if (necdefs[i][5].length > 0){//dijmane def += "<br><span style='padding-left:50px;'>Dijmane: </span>"; for (l = 0; l < necdefs[i][5].length; l++) { def += "<input type=text id='necinputD"+ l +"' size=10 value='" + necdefs[i][5][l][0] + "' onKeyUp=necdefs[" + i + "][5][" + l + "][0]=this.value;necfunction() />"; if (necdefs[i][5].length > 1){ def += ", "; } } def += "<a href=javascript:necdefs[" + i + "][5].push(['']);uNec();document.getElementById('necinputD" + l + "').focus() title='Dijmaneyekê lê zêde bike'> (+)</a>"; def += "<a href=javascript:necdefs[" + i + "][5].splice(" + (necdefs[i][5].length - 1) + ",1);uNec() title='Dijmaneyê jê bibe'> (–)</a>"; } if (necdefs[i][4].length > 0){//etîket def += "<br><span style='padding-left:50px;'>Etîket: </span>"; for (l = 0; l < necdefs[i][4].length; l++) { def += "<input type=text id='necinputE"+ l +"' size=10 value='" + necdefs[i][4][l][0] + "' onKeyUp=necdefs[" + i + "][4][" + l + "][0]=this.value;necfunction() />"; if (necdefs[i][4].length > 1){ def += ", "; } } def += "<a href=javascript:necdefs[" + i + "][4].push(['']);uNec();document.getElementById('necinputE" + l + "').focus() title='Etîketekê lê zêde bike'> (+)</a>"; def += "<a href=javascript:necdefs[" + i + "][4].splice(" + (necdefs[i][4].length - 1) + ",1);uNec() title='Etîketê jê bibe'> (–)</a>"; } for (l = 0; l < necdefs[i][1].length; l++) { //Exemple def += "<br><span style='padding-left:30px;'>Mînak: </span><input type=text size=100 value='" + necdefs[i][1][l][0] + "' onKeyUp=necdefs[" + i + "][1][" + l + "][0]=this.value;necfunction() /><a href=javascript:necdefs[" + i + "][1].splice(" + l + ",1);uNec() title='Mînakê jê bibe'> (–)</a>"; if (neccode != "ku") { if ((new LangMetadata()).guessScript(neccode) != 'Latn') { def += "<br><span style='padding-left:60px;'>Transliterasyon: </span><input type=text size=100 value='" + necdefs[i][1][l][1] + "' onKeyUp=necdefs[" + i + "][1][" + l + "][1]=this.value;necfunction() />"; } def += "<br><span style='padding-left:60px;'>Wergera mînakê: </span><input type=text size=100 value='" + necdefs[i][1][l][2] + "' onKeyUp=necdefs[" + i + "][1][" + l + "][2]=this.value;necfunction() />"; } } for (l = 0; l < necdefs[i][2].length; l++) { //jêgirtin var x = ['Şablon', 'Nivîskar', 'Sernav', 'Weşanxane', 'Rûpel', 'Malper/Hejmar/ISBN', 'URL', 'Sal']; var z = [10, 30, 50, 30, 10, 50, 55, 10]; //mides def += "<br>"; for (var y = 0; y < x.length; y++) { def += "<span style='padding-left:30px;'>" + x[y] + ": <input type=text size=" + z[y] + " value='" + necdefs[i][2][l][y] + "' onKeyUp=necdefs[" + i + "][2][" + l + "][" + y + "]=this.value;necfunction() /><br> "; } def += "</span><br><span style='padding-left:30px;'>Jêgirtin: <input type=text size=100 value='" + necdefs[i][2][l][8] + "' onKeyUp=necdefs[" + i + "][2][" + l + "][8]=this.value;necfunction() /><a href=javascript:necdefs[" + i + "][2].splice(" + l + ",1);uNec() title='Jêgirtinê jê bibe'>(–)</a>"; if (neccode != "ku") { def += "<br><span style='padding-left:60px;'>Wergera jêgirtinê: </span><input type=text size=100 value='" + necdefs[i][2][l][9] + "' onKeyUp=necdefs[" + i + "][2][" + l + "][9]=this.value;necfunction() />"; } } def += "<br>"; } document.getElementById('necdefs').innerHTML = def; } function necpostbox(q) { if (q != undefined) { if ((q > 3 && q <= 6) || q == 14 || q == 15 || q == 16) { necpost[q][necpost[q].length] = ['', '']; } else if ((q > 6 && q < 13)) { necpost[q][necpost[q].length] = ''; } else { necpost[q] = ''; } } var m = ""; /* USAGE NOTES, INFLECTION TABLES */ for (o = 0; o <= 3; o++) { if (necpost[o] != undefined) { m += "<span style='padding-left:30px;'>" + necheadingorder[o] + ": <a href=javascript:necpost[" + o + "]=undefined;"; /* if (!o) { m += "document.getElementById('necquotbutton').style.fontWeight='';"; }*/ m += "necpostbox();necfunction() title='Vê beşê jê bibe'>(jê bibe)</a></span><br><span style='padding-left:60px;'><textarea onKeyUp=necpost[" + o + "]=this.value;necfunction()>" + necpost[o] + "</textarea></span><br>"; } } /* NYMS */ for (o = 4; o < 7; o++) { if (necpost[o][0] != undefined) { m += "<span style='padding-left:30px;'>" + necheadingorder[o] + ": <a id=nec" + necheadingorder[o] + "button href=javascript:necpost[" + o + "][necpost[" + o + "].length]=['',''];necpostbox();necfunction() title=' vê beşê lê zêde bike'>(lê zêde bike)</a></span><br>"; } else if (o == 5) { document.getElementById('necSynonymsbutton').style.fontWeight = ''; } for (i = 0; i < necpost[o].length; ++i) { m += "<span style='padding-left:60px;'>Mane: <input type=text value='" + necpost[o][i][0] + "' onKeyUp=necpost[" + o + "][" + i + "][0]=this.value;necfunction() /> " + necheadingorder[o] + ": "; for (var u = 0; u < necpost[o][i].length; ++u) { if (u != 0) { if (u != 1) { m += ", "; } m += "<input type=text size=5 value='" + necpost[o][i][u] + "' onKeyUp=necpost[" + o + "][" + i + "][" + u + "]=this.value;necfunction() />"; } } m += "<a href=javascript:necpost[" + o + "][" + i + "].push('');necpostbox();necfunction() title='" + necheadingorder[o] + " lê zêde bike'> (+)</a>"; if (necpost[o][i].length > 2) { m += "<a href=javascript:necpost[" + o + "][" + i + "].splice(" + (necpost[o][i].length - 1) + ",1);necpostbox();necfunction() title='" + necheadingorder[o] + " jê bibe'> (–)</a>"; } m += "<a href=javascript:necpost[" + o + "].splice(" + i + ",1);necpostbox();necfunction() title='Vê beşê jê bibe'> (jê bibe)</a><br>"; } if (o == 10) { o = 12; } } /* DERIVED TERMS, RELATED TERMS, SEE ALSO, EXTERNAL LINKS */ for (o = 7; o <= 12; o++) { if (necpost[o][0] != undefined) { m += "<span style='padding-left:30px;'>" + necheadingorder[o] + ": <a href=javascript:necpost[" + o + "].push('');necpostbox();necfunction()>(nû)</a></span><br>"; } for (i = 0; i < necpost[o].length; ++i) { m += "<span style='padding-left:60px;'><input type=text value='" + necpost[o][i] + "' onKeyUp=necpost[" + o + "][" + i + "]=this.value;necfunction() /><a href=javascript:necpost[" + o + "].splice(" + i + ",1);necpostbox();necfunction() title='Jê bibe'>(–)</a><br>"; } if (o == 12) { o = 15 } } /* DESCENDANTS */ if (necpost[14][0] != undefined) { m += "<span style='padding-left:30px;'>" + necheadingorder[14] + ": <a href=javascript:necpost[14].push(['','']);necpostbox();necfunction() title='Dûndeyeke nû lê zêde bike'>(nû)</a></span><br>"; } for (i = 0; i < necpost[14].length; ++i) { m += "<span style='padding-left:60px;'>Koda zimanî: <input type=text value='" + necpost[14][i][0] + "' onKeyUp=necpost[14][" + i + "][0]=this.value;necfunction() onblur=if (necCleanLangCode(this.value)){this.value=necCleanLangCode(this.value)};necpost[14][" + i + "][0]=this.value;necfunction() /> Peyv: <input type=text value='" + necpost[14][i][1] + "' onKeyUp=necpost[14][" + i + "][1]=this.value;necfunction() /><a href=javascript:necpost[14].splice(" + i + ",1);necpostbox();necfunction() title='Jê bibe'>(–)</a><br>"; } /* Bi zaravayên din */ if (necpost[15][0] != undefined) { m += "<span style='padding-left:30px;'>" + necheadingorder[15] + ": <a href=javascript:necpost[15].push(['','']);necpostbox();necfunction() title='Zaravayeke nû lê zêde bike'>(nû)</a></span><br>"; } for (i = 0; i < necpost[15].length; ++i) { m += "<span style='padding-left:60px;'>Koda zimanî: <input type=text value='" + necpost[15][i][0] + "' onKeyUp=necpost[15][" + i + "][0]=this.value;necfunction() title='ckb ji bo Soranî, zza ji bo Zazakî, lki ji bo Lekî, sdh ji bo Kurdiya başûrî (Kelhûrî, Feylî, Kirmaşanî, Şêxbizinî)'/> " + necheadingorder[15] + ": "; for (var u = 0; u < necpost[15][i].length; ++u) { if (u != 0) { if (u != 1) { m += ", "; } m += "<input type=text size=5 value='" + necpost[15][i][u] + "' onKeyUp=necpost[15][" + i + "][" + u + "]=this.value;necfunction() />"; } } m += "<a href=javascript:necpost[15][" + i + "].push('');necpostbox();necfunction() title='Wergereke din lê zêde bike'> (+)</a>"; if (necpost[15][i].length > 2) { m += "<a href=javascript:necpost[15][" + i + "].splice(" + (necpost[15][i].length - 1) + ",1);necpostbox();necfunction() title='Vê wergerê jê bibe'> (–)</a>"; } m += "<a href=javascript:necpost[15].splice(" + i + ",1);necpostbox();necfunction() title='Vî zimanî jê bibe'> (jê bibe)</a><br>"; } /* TRANSLATIONS */ if (necpost[16][0] != undefined) { m += "<span style='padding-left:30px;'>" + necheadingorder[16] + ": <a id=nec" + necheadingorder[16] + "button href=javascript:necpost[16][necpost[16].length]=['',''];necpostbox();necfunction() title='Zimanekî din lê zêde bike'>(zimanekî din +)</a></span><br>"; } for (i = 0; i < necpost[16].length; ++i) { m += "<span style='padding-left:60px;'>Koda zimanî: <input type=text value='" + necpost[16][i][0] + "' onKeyUp=necpost[16][" + i + "][0]=this.value;necfunction() /> " + necheadingorder[16] + ": "; for (var u = 0; u < necpost[16][i].length; ++u) { if (u != 0) { if (u != 1) { m += ", "; } m += "<input type=text size=5 value='" + necpost[16][i][u] + "' onKeyUp=necpost[16][" + i + "][" + u + "]=this.value;necfunction() />"; } } m += "<a href=javascript:necpost[16][" + i + "].push('');necpostbox();necfunction() title='Wergereke din lê zêde bike'> (+)</a>"; if (necpost[16][i].length > 2) { m += "<a href=javascript:necpost[16][" + i + "].splice(" + (necpost[16][i].length - 1) + ",1);necpostbox();necfunction() title='Vê wergerê jê bibe'> (–)</a>"; } m += "<a href=javascript:necpost[16].splice(" + i + ",1);necpostbox();necfunction() title='Vî zimanî jê bibe'> (jê bibe)</a><br>"; } document.getElementById('necpostbox').innerHTML = m; } function necpostboxT(q) { if (q != undefined) { if (q == 5 || q == 3 || (q > 6 && q <= 8) || q == 9) { necpostT[q][necpostT[q].length] = ['', '']; } else if (q == 1 ||q == 0 ||q == 2 || q == 4 || q == 6) { necpostT[q][necpostT[q].length] = ''; } else { necpostT[q] = ''; } } var n = ""; /* Hevdeng */ if (necpostT[0][0] != undefined) { n += "<span style='padding-left:30px;'>Hevdeng: </span>"; for (i = 0; i < necpostT[0].length; ++i) { n +="<input type=text id='inputHevdeng"+ i +"' value='" + necpostT[0][i] + "' onKeyUp=necpostT[0][" + i + "]=this.value;necfunction() />"; if (necpostT[0].length > 1) { n += ", "; } } n += "<a href=javascript:necpostT[0].splice(" + (necpostT[0].length - 1) + ",1);necpostboxT();necfunction() title='Hevdengê jê bibe'> (–) </a>"; n += "<a href=javascript:necpostT[0].push('');necpostboxT();necfunction();document.getElementById('inputHevdeng" + i + "').focus() title='Hevdenga din lê zêde bike'> (+)</a>"; n += "<br>"; } /* IPA */ if (necpostT[1][0] != undefined) { for (i = 0; i < necpostT[1].length; ++i) { n += "<span style='padding-left:30px;'>IPA:<input type=text value='" + necpostT[1][i] + "' onKeyUp=necpostT[1][" + i + "]=this.value;necfunction() /><a href=javascript:necpostT[1].splice(" + i + ",1);necpostboxT();necfunction() title='IPAyê jê bibe'> (–) </a>"; if (i == 0) { n += "<a href=javascript:necpostT[1].push('');necpostboxT();necfunction() title='IPAya din lê zêde bike'> (+IPA nû)</a>"; } n += "</span><br>"; } } /* Kîtekirin */ if (necpostT[2][0] != undefined) { n += "<span style='padding-left:30px;'>Kîtekirin: </span>"; for (i = 0; i < necpostT[2].length; ++i) { n +="<input type=text id='inputKîte"+ i +"' value='" + necpostT[2][i] + "' onKeyUp=necpostT[2][" + i + "]=this.value;necfunction() />"; if (necpostT[2].length > 1) { n += ", "; } } n += "<a href=javascript:necpostT[2].splice(" + (necpostT[2].length - 1) + ",1);necpostboxT();necfunction() title='Kîtekirinê jê bibe'> (–) </a>"; n += "<a href=javascript:necpostT[2].push('');necpostboxT();necfunction();document.getElementById('inputKîte" + i + "').focus() title='Kîteya din lê zêde bike'> (+)</a>"; n += "<br>"; } /* Deng */ if (necpostT[3][0] != undefined) { for (i = 0; i < necpostT[3].length; ++i) { n += "<span style='padding-left:30px;'>Navê dosyeyê:<input type=text value='" + necpostT[3][i][0] + "' onKeyUp=necpostT[3][" + i + "][0]=this.value;necfunction() /> Dever:<input type=text value='" + necpostT[3][i][1] + "' onKeyUp=necpostT[3][" + i + "][1]=this.value;necfunction() /><a href=javascript:necpostT[3].splice(" + i + ",1);necpostboxT();necfunction() title='Dengî jê bibe'> (–)</a>"; if (i == 0) { n += "<a href=javascript:necpostT[3].push(['','']);necpostboxT();necfunction() title='Dengekî nû lê zêde bike'> (+dengê nû)</a>"; } n += "</span><br>"; } } /* Kategorî */ if (necpostT[4][0] != undefined) { for (i = 0; i < necpostT[4].length; ++i) { n += "<span style='padding-left:30px;'>Kategorî:<input type=text value='" + necpostT[4][i] + "' onKeyUp=necpostT[4][" + i + "]=this.value;necfunction() /><a href=javascript:necpostT[4].splice(" + i + ",1);necpostboxT();necfunction() title='Kategoriyê jê bibe'> (–) </a>"; if (i == 0) { n += "<a href=javascript:necpostT[4].push('');necpostboxT();necfunction() title='Kategoriyeke nû lê zêde bike'> (+kategoriya nû) </a>"; } n += "</span><br>"; } } /* Wîkîpediyayê */ if (necpostT[5][0] != undefined) { for (i = 0; i < necpostT[5].length; ++i) { n += "<span style='padding-left:30px;'>Rûpela Wîkîpediyayê:<input type=text value='" + necpostT[5][i][0] + "' onKeyUp=necpostT[5][" + i + "][0]=this.value;necfunction() /> Rûpela Wîkîferhengê:<input type=text value='" + necpostT[5][i][1] + "' onKeyUp=necpostT[5][" + i + "][1]=this.value;necfunction() /><a href=javascript:necpostT[5].splice(" + i + ",1);necpostboxT();necfunction() title='Şablonê jê bibe'> (–)</a>"; /* if (i == 0) { n += "<a href=javascript:necpostT[5].push(['','']);necpostboxT();necfunction() title='Wêneyekî nû lê zêde bike'> (+wêneyê nû)</a>"; }*/ n += "</span><br>"; } } /* Binêre herwiha */ if (necpostT[6][0] != undefined) { for (i = 0; i < necpostT[6].length; ++i) { n += "<span style='padding-left:30px;'>Binêre:<input type=text value='" + necpostT[6][i] + "' onKeyUp=necpostT[6][" + i + "]=this.value;necfunction() /><a href=javascript:necpostT[6].splice(" + i + ",1);necpostboxT();necfunction() title='Peyvê jê bibe'> (–) </a>"; if (i == 0) { n += "<a href=javascript:necpostT[6].push('');necpostboxT();necfunction() title='lê zêde bike'> (+yekî din) </a>"; } n += "</span><br>"; } } /* Wêne */ if (necpostT[7][0] != undefined) { for (i = 0; i < necpostT[7].length; ++i) { n += "<span style='padding-left:30px;'>Navê dosyeyê:<input type=text value='" + necpostT[7][i][0] + "' onKeyUp=necpostT[7][" + i + "][0]=this.value;necfunction() /> Sernavê wêneyî:<input type=text value='" + necpostT[7][i][1] + "' onKeyUp=necpostT[7][" + i + "][1]=this.value;necfunction() /><a href=javascript:necpostT[7].splice(" + i + ",1);necpostboxT();necfunction() title='Wêneyî jê bibe'> (–)</a>"; if (i == 0) { n += "<a href=javascript:necpostT[7].push(['','']);necpostboxT();necfunction() title='Wêneyekî nû lê zêde bike'> (+wêneyê nû)</a>"; } n += "</span><br>"; } } /* Etîmolojî: [[şablon:ji]] */ if (necpostT[8][0] != undefined) { for (i = 0; i < necpostT[8].length; ++i) { n += "<span style='padding-left:30px;'>"; n += "Şablon: <input type=text value='" + necpostT[8][i][0] + "' size=5 onKeyUp=necpostT[8][" + i + "][0]=this.value;necfunction() /> "; n += "Zimanê jêder: <input type=text value='" + necpostT[8][i][1] + "' size=5 onKeyUp=necpostT[8][" + i + "][1]=this.value;necfunction() /> "; n += "Peyv: <input type=text size=5 value='" + necpostT[8][i][2] + "' onKeyUp=necpostT[8][" + i + "][2]=this.value;necfunction() />" ; n += "Mane: <input type=text size=5 value='" + necpostT[8][i][3] + "' onKeyUp=necpostT[8][" + i + "][3]=this.value;necfunction() />"; n += "Translîterasyon: <input type=text size=5 value='" + necpostT[8][i][4] + "' onKeyUp=necpostT[8][" + i + "][4]=this.value;necfunction() />"; n += "<a href=javascript:necpostT[8].splice(" + i + ",1);necpostboxT();necfunction() title='Şablonê jê bibe'> (–)</a>"; if (i == 0) { n += "<a href=javascript:necpostT[8].push(['','']);necpostboxT();necfunction() title='Lê zêde bike'> (+)</a>"; } n += "</span><br>"; } } /* Etîmolojî: [[şablon:qertaf]] */ if (necpostT[9][0] != undefined) { for (i = 0; i < necpostT[9].length; ++i) { n += "<span style='padding-left:30px;'>Qertaf #1: <input type=text size=10 value='" + necpostT[9][i][0] + "' onKeyUp=necpostT[9][" + i + "][0]=this.value;necfunction() /> Qertaf #2: <input type=text value='" + necpostT[9][i][1] + "' onKeyUp=necpostT[9][" + i + "][1]=this.value;necfunction() /> Maneya #1: <input type=text size=10 value='" + necpostT[9][i][2] + "' onKeyUp=necpostT[9][" + i + "][2]=this.value;necfunction() /> Maneya #2: <input type=text size=10 value='" + necpostT[9][i][3] + "' onKeyUp=necpostT[9][" + i + "][3]=this.value;necfunction() />TR #1: <input type=text size=10 value='" + necpostT[9][i][4] + "' onKeyUp=necpostT[9][" + i + "][4]=this.value;necfunction() /> TR #2: <input type=text size=10 value='" + necpostT[9][i][5] + "' onKeyUp=necpostT[9][" + i + "][5]=this.value;necfunction() /><a href=javascript:necpostT[9].splice(" + i + ",1);necpostboxT();necfunction() title='Şablonê jê bibe'> (–)</a>"; if (i == 0) { n += "<a href=javascript:necpostT[9].push(['','']);necpostboxT();necfunction() title='Lê zêde bike'> (+)</a>"; } n += "</span><br>"; } } document.getElementById('necpostboxT').innerHTML = n; } function necfunction6(cc, dd) { document.getElementById('necinput' + cc + necdata[cc]).style.fontWeight = ''; necdata[cc] = document.getElementById(dd).value; document.getElementById(dd).parentNode.setAttribute('ID', 'necinput' + cc + document.getElementById(dd).value); document.getElementById('necinput' + cc + necdata[cc]).style.fontWeight = 'bold'; } function necfunction7(qw, er) { var qwe = false; for (var ty in qw) { if (er == qw[ty][0]) { qwe = true; } } return qwe; } function uNec() { necdefupdate(); necfunction(); } jQuery(document).ready(function necload() { if (document.getElementById('necblah')) { necfunction2(); necdefupdate(); necfunction(); necfunction4(); necfunction(); } }); function wikilinkText() { var sel; if (window.getSelection) { sel = window.getSelection(); var activeElement = document.activeElement; if (activeElement.nodeName == "TEXTAREA" || (activeElement.nodeName == "INPUT" && activeElement.type.toLowerCase() == "text")) { var val = activeElement.value, start = activeElement.selectionStart, end = activeElement.selectionEnd; activeElement.value = val.slice(0, start) + '[[' + sel + ']]' + val.slice(end); } } } function wikiText() { var sel; if (window.getSelection) { sel = window.getSelection(); var activeElement = document.activeElement; if (activeElement.nodeName == "TEXTAREA" || (activeElement.nodeName == "INPUT" && activeElement.type.toLowerCase() == "text")) { var val = activeElement.value, start = activeElement.selectionStart, end = activeElement.selectionEnd; activeElement.value = val.slice(0, start) + '{{' + sel + '}}' + val.slice(end); } } } function wikiPipe() { var sel; if (window.getSelection) { sel = window.getSelection(); var activeElement = document.activeElement; if (activeElement.nodeName == "TEXTAREA" || (activeElement.nodeName == "INPUT" && activeElement.type.toLowerCase() == "text")) { var val = activeElement.value, start = activeElement.selectionStart, end = activeElement.selectionEnd; activeElement.value = val.slice(0, start) + '|' + val.slice(end); } } } function LangMetadata() { //Singleton if (arguments.callee.instance) return arguments.callee.instance; else arguments.callee.instance = this; // {{{ Metadata dictionaries var metadata = { aa: { hw: 1, sc: ["Latn", "Ethi"] }, ab: { hw: 1, sc: ["Cyrl", "Latn", "Geor"] }, aer: { sc: "Latn" }, af: { g: "", hw: 1, p: 1, sc: "Latn" }, ak: { hw: 1 }, akk: { g: "mf", p: 1, sc: "Xsux" }, als: { hw: 1 }, am: { g: "mf", hw: 1, p: 1, sc: "Ethi" }, an: { g: "mf", hw: 1, p: 1, sc: "Latn" }, ang: { alt: 1, g: "mfn", hw: 1, p: 1, sc: "Latn" }, ar: { alt: 1, g: "mf", hw: 1, p: 1, sc: "Arab" }, arc: { g: "mf", p: 1, sc: "Hebr" }, are: { sc: "Latn" }, arz: { alt: 1, g: "mf", p: 1, sc: "Arab" }, as: { hw: 1, sc: "Beng" }, ast: { g: "mf", hw: 1, p: 1, sc: "Latn" }, av: { hw: 1, sc: "Cyrl" }, axm: { alt: 0, g: "", sc: "Armn" }, ay: { hw: 1 }, az: { alt: 0, g: "", hw: 1, p: 1, sc: ["Latn", "Cyrl", "Arab"] }, ba: { sc: "Cyrl" }, bar: { sc: "Latn" }, "bat-smg": { g: "mf", p: 1, sc: "Latn" }, be: { g: "mfn", hw: 1, p: 1, sc: ["Cyrl", "Latn"] }, "be-x-old": { sc: "Cyrl" }, bg: { g: "mfn", hw: 1, p: 1, sc: "Cyrl" }, bh: { hw: 1, sc: "Deva" }, bhb: { sc: "Deva" }, bi: { hw: 1, sc: "Latn" }, blt: { sc: "Tavt" }, bm: { hw: 1, sc: ["Latn", "Nkoo", "Arab"] }, bn: { g: "", hw: 1, sc: "Beng" }, bo: { hw: 1, sc: "Tibt" }, br: { g: "mf", hw: 1, sc: "Latn" }, bs: { alt: 1, g: "mfn", hw: 1, p: 1, sc: ["Latn"] }, ca: { g: "mf", hw: 1, p: 1, sc: "Latn" }, cdo: { g: "", p: 0, sc: "Hani" }, ch: { hw: 1, sc: "Latn" }, chr: { hw: 1, sc: "Cher" }, cjy: { g: "", p: 0, sc: "Hani" }, ckb: { sc: "Arab", wsc: "ku-Arab" }, cmn: { g: "", hw: 1, p: 0, sc: "Hani" }, co: { hw: 1, sc: "Latn" }, cpx: { g: "", p: 0, sc: "Hani" }, cr: { hw: 1, sc: "Cans" }, crh: { alt: 0, g: "", sc: "Latn" }, cs: { g: "mfn", hw: 1, p: 1, sc: "Latn" }, csb: { hw: 1 }, cu: { g: "mfn", p: 1, sc: ["Cyrs", "Glag"] }, cv: { alt: 0, g: "", sc: "Cyrl" }, cy: { g: "mf", hw: 1, p: 1, sc: "Latn" }, czh: { g: "", p: 0, sc: "Hani" }, czo: { g: "", p: 0, sc: "Hani" }, da: { g: "cn", hw: 1, p: 1, sc: "Latn" }, dax: { sc: "Latn" }, de: { g: "mfn", hw: 1, p: 1, sc: "Latn" }, dhg: { sc: "Latn" }, djb: { sc: "Latn" }, dji: { sc: "Latn" }, djr: { sc: "Latn" }, dng: { g: "", p: 0, sc: "Cyrl" }, dsx: { sc: "Latn" }, duj: { sc: "Latn" }, dv: { hw: 1, p: 1, sc: "Thaa" }, dz: { hw: 1, sc: "Tibt" }, el: { g: "mfn", hw: 1, p: 1, sc: "Grek" }, en: { g: "", hw: 1, p: 1, sc: "Latn" }, eo: { g: "", hw: 1, p: 1, sc: "Latn" }, es: { alt: 0, g: "mf", hw: 1, p: 1, sc: "Latn" }, et: { alt: 0, g: "", hw: 1, p: 1, sc: "Latn" }, ett: { p: 1, sc: "Ital" }, eu: { alt: 0, g: "", hw: 1, p: 1, sc: "Latn" }, fa: { g: "", hw: 1, sc: "Arab", wsc: "fa-Arab" }, fi: { g: "", hw: 1, p: 1, sc: "Latn" }, fil: { g: "", p: 0, sc: "Latn" }, fj: { hw: 1, sc: "Latn" }, fo: { g: "mfn", hw: 1, sc: "Latn" }, fr: { alt: 0, g: "mf", hw: 1, p: 1, sc: "Latn" }, frm: { alt: 0, g: "mf", p: 1, sc: "Latn" }, fro: { alt: 0, g: "mf", p: 1, sc: "Latn" }, fy: { hw: 1, sc: "Latn" }, ga: { g: "mf", hw: 1, p: 1, sc: "Latn" }, gan: { g: "", p: 0, sc: "Hani" }, gd: { g: "mf", hw: 1, p: 1, sc: "Latn" }, gez: { sc: "Ethi" }, gl: { g: "mf", hw: 1, p: 1, sc: "Latn" }, gmy: { sc: "Linb" }, gn: { hw: 1 }, gnn: { sc: "Latn" }, got: { g: "mfn", p: 1, sc: "Goth" }, grc: { g: "mfn", p: 1, sc: "Grek", wsc: "polytonic" }, gu: { g: "mfn", hw: 1, p: 1, sc: "Gujr" }, guf: { sc: "Latn" }, gv: { hw: 1 }, ha: { hw: 1 }, hak: { g: "", p: 0, sc: "Hani" }, har: { sc: "Ethi" }, he: { alt: 1, g: "mf", hw: 1, p: 1, sc: "Hebr" }, hi: { g: "mf", hw: 1, p: 1, sc: "Deva" }, hif: { sc: ["Latn", "Deva"] }, hit: { sc: "Xsux" }, hr: { alt: 1, g: "mfn", hw: 1, p: 1, sc: ["Latn"] }, hsb: { hw: 1 }, hsn: { g: "", p: 0, sc: "Hani" }, hu: { alt: 0, g: "", hw: 1, p: 1, sc: "Latn" }, hy: { alt: 0, g: "", hw: 1, sc: "Armn" }, ia: { alt: 0, g: "", hw: 1, sc: "Latn" }, id: { hw: 1, sc: "Latn" }, ie: { alt: 0, g: "", hw: 1, sc: "Latn" }, ik: { hw: 1 }, ike: { sc: "Cans" }, ikt: { sc: "Cans" }, io: { hw: 1 }, is: { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, it: { alt: 0, g: "mf", hw: 1, p: 1, sc: "Latn" }, iu: { hw: 1, sc: "Cans" }, ja: { alt: 0, g: "", hw: 1, p: 0, sc: "Jpan" }, jay: { sc: "Latn" }, jbo: { hw: 1, sc: "Latn" }, jv: { hw: 1 }, ka: { alt: 0, g: "", hw: 1, sc: "Geor" }, khb: { sc: "Talu" }, kjh: { sc: "Cyrl" }, kk: { alt: 0, g: "", hw: 1, sc: "Cyrl" }, kl: { hw: 1 }, km: { hw: 1, sc: "Khmr" }, kn: { hw: 1, sc: "Knda" }, kmr: { hw: 1, sc: "Latn" }, ko: { alt: 0, g: "", hw: 1, p: 0, sc: "Kore" }, krc: { alt: 0, g: "", p: 1, sc: "Cyrl" }, ks: { hw: 1, sc: ["Arab", "Deva"], wsc: "ks-Arab" }, ku: { hw: 1, sc: "Latn" }, kw: { hw: 1 }, ky: { alt: 0, g: "", hw: 1, sc: "Cyrl" }, la: { alt: 1, g: "mfn", hw: 1, p: 1, sc: "Latn" }, lb: { hw: 1 }, lez: { sc: "Cyrl" }, li: { hw: 1 }, ln: { hw: 1 }, lo: { alt: 0, g: "", hw: 1, p: 0, sc: "Laoo" }, lt: { alt: 1, g: "mf", hw: 1, p: 1, sc: "Latn" }, lv: { alt: 0, g: "mf", hw: 1, p: 1, sc: "Latn" }, mg: { hw: 1 }, mh: { hw: 1 }, mi: { alt: 0, g: 0, hw: 1, sc: "Latn" }, mk: { g: "mfn", hw: 1, p: 1, sc: "Cyrl" }, ml: { g: "", hw: 1, sc: "Mlym" }, mn: { alt: 0, g: "", hw: 1, sc: ["Cyrl", "Mong"] }, mnp: { g: "", p: 0, sc: "Hani" }, mo: { hw: 1, sc: "Cyrl" }, mol: { sc: "Cyrl" }, mr: { g: "mfn", hw: 1, sc: "Deva" }, ms: { hw: 1, sc: ["Latn", "Arab"] }, mt: { g: "mf", hw: 1, sc: "Latn" }, mwp: { sc: "Latn" }, my: { hw: 1, sc: "Mymr" }, na: { hw: 1 }, nah: { hw: 1 }, nan: { g: "", hw: 1, p: 0, sc: "Hani" }, nb: { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, nds: { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, "nds-de": { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, "nds-nl": { alt: 0, g: "mfn", hw: 0, p: 1, sc: "Latn" }, ne: { hw: 1, sc: "Deva" }, nl: { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, nn: { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, no: { alt: 0, g: "mfn", hw: 1, p: 1, sc: "Latn" }, non: { g: "mfn", p: 1, sc: "Latn" }, oc: { g: "mf", hw: 1, p: 1, sc: "Latn" }, om: { hw: 1 }, or: { hw: 1, sc: "Orya" }, os: { alt: 0, g: "", sc: "Cyrl" }, osc: { sc: "Ital" }, ota: { sc: "Arab", wsc: "ota-Arab" }, pa: { g: "mf", hw: 1, p: 1, sc: ["Guru", "Arab"] }, peo: { sc: "Xpeo" }, phn: { sc: "Phnx" }, pi: { hw: 1 }, pjt: { sc: "Latn" }, pl: { g: "mfn", hw: 1, p: 1, sc: "Latn" }, ps: { hw: 1, sc: "Arab", wsc: "ps-Arab" }, pt: { alt: 0, g: "mf", hw: 1, p: 1, sc: "Latn" }, qu: { hw: 1 }, rit: { sc: "Latn" }, rm: { g: "mf", hw: 1, sc: "Latn" }, rn: { hw: 1 }, ro: { g: "mfn", hw: 1, p: 1, sc: ["Latn", "Cyrl"] }, "roa-rup": { hw: 1 }, ru: { alt: 1, g: "mfn", hw: 1, p: 1, sc: "Cyrl" }, ruo: { g: "mfn", p: 1, sc: "Latn" }, rup: { g: "mfn", hw: 1, p: 1, sc: "Latn" }, ruq: { g: "mfn", p: 1, sc: "Latn" }, rw: { hw: 1, sc: "Latn" }, sa: { g: "mfn", hw: 1, p: 1, sc: "Deva" }, sah: { sc: "Cyrl" }, sc: { hw: 1 }, scn: { g: "mf", hw: 1, p: 1, sc: "Latn" }, sco: { sc: "Latn" }, sd: { hw: 1, sc: "Arab", wsc: "sd-Arab" }, sg: { hw: 1 }, sh: { alt: 1, g: "mfn", hw: 1, p: 1, sc: ["Latn", "Cyrl"] }, si: { hw: 1, sc: "Sinh" }, simple: { hw: 1, sc: "Latn" }, sk: { g: "mfn", hw: 1, p: 1, sc: "Latn" }, sl: { alt: 1, g: "mfn", hw: 1, p: 1, sc: "Latn" }, sm: { hw: 1 }, sn: { hw: 1 }, so: { hw: 1 }, spx: { sc: "Ital" }, sq: { alt: 0, g: "mf", hw: 1, sc: "Latn" }, sr: { alt: 1, g: "mfn", hw: 1, p: 1, sc: ["Cyrl"] }, ss: { hw: 1 }, st: { hw: 1 }, su: { hw: 1 }, sux: { sc: "Xsux" }, sv: { alt: 0, g: "cn", hw: 1, p: 1, sc: "Latn" }, sw: { alt: 0, g: "", hw: 1, sc: "Latn" }, syc: { sc: "Syrc" }, syr: { sc: "Syrc" }, ta: { alt: 0, g: "", hw: 1, sc: "Taml" }, tdd: { sc: "Tale" }, te: { alt: 0, g: "", hw: 1, sc: "Telu" }, tg: { alt: 0, g: "", hw: 1, sc: "Cyrl" }, th: { alt: 0, g: "", hw: 1, p: 0, sc: "Thai" }, ti: { hw: 1, sc: "Ethi" }, tig: { sc: "Ethi" }, tiw: { sc: "Latn" }, tk: { alt: 0, g: "", hw: 1, sc: "Latn" }, tl: { g: "", hw: 1, p: 0, sc: ["Latn", "Tglg"] }, tmr: { sc: "Hebr" }, tn: { hw: 1 }, to: { hw: 1 }, tpi: { hw: 1, sc: "Latn" }, tr: { alt: 1, g: "", hw: 1, p: 1, sc: "Latn" }, ts: { hw: 1 }, tt: { alt: 0, g: "", hw: 1, sc: "Cyrl" }, tw: { hw: 1 }, ug: { hw: 1, sc: "Arab", wsc: "ug-Arab" }, uga: { sc: "Ugar" }, uk: { g: "mfn", hw: 1, p: 1, sc: "Cyrl" }, ulk: { sc: "Latn" }, ur: { g: "mf", hw: 1, p: 1, sc: "Arab", wsc: "ur-Arab" }, uz: { alt: 0, g: "", hw: 1, sc: "Latn" }, vi: { g: "", hw: 1, p: 0, sc: "Latn" }, vls: { alt: 0, g: "mfn", hw: 0, p: 1, sc: "Latn" }, vo: { hw: 1 }, wa: { hw: 1 }, wbp: { sc: "Latn" }, wo: { hw: 1 }, wuu: { g: "", p: 0, sc: "Hani" }, xae: { sc: "Ital" }, xcl: { alt: 0, g: "", sc: "Armn" }, xcr: { sc: "Cari" }, xfa: { sc: "Ital" }, xh: { hw: 1 }, xlc: { sc: "Lyci" }, xld: { sc: "Lydi" }, xlu: { sc: "Xsux" }, xno: { alt: 0, g: "mf", p: 1, sc: "Latn" }, xrr: { sc: "Ital" }, xst: { sc: "Ethi" }, xum: { sc: "Ital" }, xve: { sc: "Ital" }, xvo: { sc: "Ital" }, yi: { g: "mfn", hw: 1, p: 1, sc: "Hebr" }, yo: { hw: 1 }, yua: { alt: 1, g: "", p: 1, sc: "Latn" }, yue: { g: "", p: 0, sc: "Hani" }, za: { hw: 1 }, "zh-classical": { sc: "Hani" }, "zh-min-nan": { hw: 1, sc: "Latn" }, "zh-yue": { sc: "Hani" }, zu: { alt: 1, nc: 1, hw: 1, sc: "Latn"} }; var clean = { aar: "aa", afar: "aa", abk: "ab", abkhazian: "ab", afr: "af", afrikaans: "af", aka: "ak", akan: "ak", amh: "am", amharic: "am", ara: "ar", arabic: "ar", arg: "an", aragonese: "an", asm: "as", assamese: "as", ava: "av", avaric: "av", ave: "ae", avestan: "ae", aym: "ay", aymara: "ay", aze: "az", azerbaijani: "az", bak: "ba", bashkir: "ba", bam: "bm", bambara: "bm", bel: "be", belarusian: "be", ben: "bn", bengali: "bn", bis: "bi", bislama: "bi", bod: "bo", tibetan: "bo", bos: "bs", bosnian: "bs", bre: "br", breton: "br", bul: "bg", bulgarian: "bg", cat: "ca", catalan: "ca", ces: "cs", czech: "cs", cha: "ch", chamorro: "ch", che: "ce", chechen: "ce", chu: "cu", churchslavic: "cu", chv: "cv", chuvash: "cv", cor: "kw", cornish: "kw", cos: "co", corsican: "co", cre: "cr", cree: "cr", cym: "cy", welsh: "cy", dan: "da", danish: "da", deu: "de", german: "de", div: "dv", dhivehi: "dv", dzo: "dz", dzongkha: "dz", ell: "el", greek: "el", eng: "en", english: "en", epo: "eo", esperanto: "eo", est: "et", estonian: "et", eus: "eu", basque: "eu", ewe: "ee", fao: "fo", faroese: "fo", fas: "fa", persian: "fa", fij: "fj", fijian: "fj", fil: "tl", fin: "fi", finnish: "fi", fra: "fr", french: "fr", fry: "fy", westernfrisian: "fy", ful: "ff", fulah: "ff", gla: "gd", scottishgaelic: "gd", gle: "ga", irish: "ga", glg: "gl", galician: "gl", glv: "gv", manx: "gv", grn: "gn", guarani: "gn", guj: "gu", gujarati: "gu", hat: "ht", haitian: "ht", hau: "ha", hausa: "ha", heb: "he", hebrew: "he", her: "hz", herero: "hz", hin: "hi", hindi: "hi", hmo: "ho", hirimotu: "ho", hrv: "hr", croatian: "hr", hun: "hu", hungarian: "hu", hye: "hy", armenian: "hy", ibo: "ig", igbo: "ig", ido: "io", iii: "ii", sichuanyi: "ii", iku: "iu", inuktitut: "iu", ile: "ie", interlingue: "ie", ina: "ia", interlingua: "ia", ind: "id", indonesian: "id", ipk: "ik", inupiaq: "ik", isl: "is", icelandic: "is", ita: "it", italian: "it", jav: "jv", javanese: "jv", jpn: "ja", japanese: "ja", kal: "kl", kalaallisut: "kl", kan: "kn", kannada: "kn", kas: "ks", kashmiri: "ks", kat: "ka", georgian: "ka", kau: "kr", kanuri: "kr", kaz: "kk", kazakh: "kk", khm: "km", centralkhmer: "km", kik: "ki", kikuyu: "ki", kin: "rw", kinyarwanda: "rw", kir: "ky", kirghiz: "ky", kom: "kv", komi: "kv", kon: "kg", kongo: "kg", kor: "ko", korean: "ko", kua: "kj", kuanyama: "kj", kur: "ku", kurdish: "ku", lao: "lo", lat: "la", latin: "la", lav: "lv", latvian: "lv", lim: "li", limburgan: "li", lin: "ln", lingala: "ln", lit: "lt", lithuanian: "lt", ltz: "lb", luxembourgish: "lb", lub: "lu", lubakatanga: "lu", lug: "lg", ganda: "lg", mah: "mh", marshallese: "mh", mal: "ml", malayalam: "ml", mar: "mr", marathi: "mr", mkd: "mk", macedonian: "mk", mlg: "mg", malagasy: "mg", mlt: "mt", maltese: "mt", mon: "mn", mongolian: "mn", mri: "mi", maori: "mi", msa: "ms", malay: "ms", mya: "my", burmese: "my", nau: "na", nauru: "na", lowgerman: "nds", wep: "nds", westphalian: "nds", germanlowgerman: "nds-de", dutchlowsaxon: "nds-nl", act: "nds-nl", achterhoeks: "nds-nl", drt: "nds-nl", drents: "nds-nl", gos: "nds-nl", gronings: "nds-nl", sdz: "nds-nl", sallands: "nds-nl", stl: "nds-nl", stellingwerfs: "nds-nl", twd: "nds-nl", twents: "nds-nl", vel: "nds-nl", veluws: "nds-nl", nav: "nv", navajo: "nv", nbl: "nr", southndebele: "nr", nde: "nd", northndebele: "nd", ndo: "ng", ndonga: "ng", nep: "ne", nepali: "ne", nld: "nl", dutch: "nl", flemish: "nl", nno: "nn", norwegiannynorsk: "nn", nob: "nb", norwegianbokmal: "nb", nor: "no", norwegian: "no", nya: "ny", nyanja: "ny", oci: "oc", occitan: "oc", oji: "oj", ojibwa: "oj", ori: "or", oriya: "or", orm: "om", oromo: "om", oss: "os", ossetian: "os", pan: "pa", panjabi: "pa", pli: "pi", pali: "pi", pol: "pl", polish: "pl", por: "pt", portuguese: "pt", pus: "ps", pushto: "ps", que: "qu", quechua: "qu", roh: "rm", romansh: "rm", ron: "ro", romanian: "ro", run: "rn", rundi: "rn", rus: "ru", russian: "ru", sag: "sg", sango: "sg", san: "sa", sanskrit: "sa", sin: "si", sinhala: "si", slk: "sk", slovak: "sk", slv: "sl", slovenian: "sl", sme: "se", northernsami: "se", smo: "sm", samoan: "sm", sna: "sn", shona: "sn", snd: "sd", sindhi: "sd", som: "so", somali: "so", sot: "st", southernsotho: "st", spa: "es", spanish: "es", sqi: "sq", albanian: "sq", srd: "sc", sardinian: "sc", srp: "sr", serbian: "sr", ssw: "ss", swati: "ss", sun: "su", sundanese: "su", swa: "sw", swahili: "sw", swe: "sv", swedish: "sv", tah: "ty", tahitian: "ty", tam: "ta", tamil: "ta", tat: "tt", tatar: "tt", tel: "te", telugu: "te", tgk: "tg", tajik: "tg", tgl: "tl", tagalog: "tl", tha: "th", thai: "th", tir: "ti", tigrinya: "ti", ton: "to", tonga: "to", tsn: "tn", tswana: "tn", tso: "ts", tsonga: "ts", tuk: "tk", turkmen: "tk", tur: "tr", turkish: "tr", twi: "tw", uig: "ug", uighur: "ug", ukr: "uk", ukrainian: "uk", urd: "ur", urdu: "ur", uzb: "uz", uzbek: "uz", ven: "ve", venda: "ve", vie: "vi", vietnamese: "vi", westflemish: "vls", vol: "vo", volapuk: "vo", wln: "wa", walloon: "wa", wol: "wo", wolof: "wo", xho: "xh", xhosa: "xh", yid: "yi", yiddish: "yi", yor: "yo", yoruba: "yo", zha: "za", zhuang: "za", zho: "zh", chinese: "zh", zul: "zu", zulu: "zu" }; // }}} // FIXME: merge into above var a = '{{ar}}', c = '{{zh}}', d = '{{de}}'; var nesting = { ang: '{{en}}',// enm:'English', don't nest English (Encyclopetey) gmh: d, goh: d, //gsw: 'German', ksh: 'German', pfl: 'German', sxu: 'German', nb: '{{no}}', nn: '{{no}}', dsb: '{{wen}}', hsb: '{{wen}}', 'zh-tw': c, 'zh-cn': c, yue: c, dng: c, gan: c, hak: c, czh: c, cjy: c, cmn: c, mnp: c, cdo: c, nan: c, czo: c, cpx: c, wuu: c, hsn: c, lzh: c, arq: a, aao: a, bbz: a, abv: a, shu: a, acy: a, adf: a, avl: a, arz: a, afb: a, ayh: a, acw: a, ayl: a, acm: a, ary: a, ars: a, apc: a, ayp: a, acx: a, aec: a, ayn: a, ssh: a, ajp: a, arb: a, apd: a, pga: a, acq: a, abh: a, aeb: a, auz: a }; //Given a language code return a default script code. this.guessScript = function (lang) { if (metadata[lang]) { // enwikt language template? (ur-Arab, polytonic) if (metadata[lang].wsc) { return metadata[lang].wsc; } // ISO script code? (Arab, Grek) if (metadata[lang].sc) { if (typeof metadata[lang].sc == 'object') return metadata[lang].sc[0]; else return metadata[lang].sc; } } return false; }; } // end LangMetadata // </nowiki> e7hqn4hqljf1xczmyisvqmx69ghhsff hevalê 0 969734 6291668 6276885 2026-07-27T16:00:39Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291668 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{IPA|ku|/hɛˈvɑːleː/}} * {{ku-kîte}} === Formeke navdêrê === {{ku-tew-nav|heval|mê û nêr}} {{navdêr|ku|form=erê}} # {{ku-tewîna-nav|heval|mê û nêr}} apy2fk4sy0hktyht2zbib7u1h5yq4x3 Bikarhêner:Wikihez/minerva.js 2 970182 6291723 6241655 2026-07-27T22:10:22Z Wikihez 7344 6291723 javascript text/javascript /** * Skripta Wîkîferhengê: Lînkên sor û bişkoka guhartinê ya mobîl * Kar: Hemû lînkên sor û bişkoka guhartinê ya mobîl bi 'action=submit' vedike. */ (function () { function fixLinks() { // 1. Hemû lînkên sor (redlinks) diguherîne $('a.new').each(function () { var href = $(this).attr('href'); if (href) { // 'action=edit' diguherîne 'action=submit' $(this).attr('href', href.replace('action=edit', 'action=submit')); } }); // 2. Tenê ji bo mobîlê (Skin: MinervaNeue) if (mw.config.get('skin') === 'minerva' || $('body').hasClass('skin-minerva')) { // Li ser mobîlê bişkoka guhartinê ya sereke û ya beşan diguherîne $('#ca-edit, .edit-page, .mw-editsection a').each(function () { var href = $(this).attr('href'); if (href && href.indexOf('action=') !== -1) { $(this).attr('href', href.replace(/action=[^&]+/, 'action=submit')); } else if (href) { // Heke action tune be (mînak lînka sereke), lê zêde dike var connector = href.indexOf('?') !== -1 ? '&' : '?'; $(this).attr('href', href + connector + 'action=submit'); } }); } } // Gava rûpel bar kir yan naverok hat guhartin (ji bo popups/live previews) $(document).ready(fixLinks); mw.hook('wikipage.content').add(fixLinks); })(); ddu09gr3apl6uj4nsia2be3yb0ttpcv 6291732 6291723 2026-07-27T22:40:25Z Wikihez 7344 6291732 javascript text/javascript /** * Gadget-ForceWikiEditor.js * Rewrites redlinks and edit buttons/icons to use action=submit, * and pre-empts MobileFrontend's overlay click handler so the * browser navigates to the classic edit form (with WikiEditor) * instead of opening the mobile overlay/VE. */ ( function () { 'use strict'; // Selectors covering redlinks + the various edit entry points // across Minerva/Vector/mobile diff/section-edit UI. var EDIT_SELECTOR = [ 'a.new', // redlinks '.mw-editsection a', // [edit] section links '#ca-edit a', // desktop tab '#ca-ve-edit a', // VE tab if present '.edit-page', // Minerva bottom edit button '.mw-ui-icon-edit', // Minerva pencil icons '.oo-ui-icon-edit', // OOUI edit icon buttons wrapping a link 'a[href*="action=edit"]' // catch-all by href ].join( ',' ); function toSubmitUrl( href ) { if ( !href ) { return href; } try { var url = new URL( href, window.location.origin ); var action = url.searchParams.get( 'action' ); if ( action === 'edit' || !action ) { url.searchParams.set( 'action', 'submit' ); } return url.toString(); } catch ( e ) { return href; } } function rewriteLinks( $context ) { $context.find( EDIT_SELECTOR ).addBack( EDIT_SELECTOR ).each( function () { var $a = $( this ); var href = $a.attr( 'href' ); if ( href ) { $a.attr( 'href', toSubmitUrl( href ) ); } } ); } // 1. Rewrite hrefs whenever content is (re)rendered. mw.hook( 'wikipage.content' ).add( function ( $content ) { rewriteLinks( $content ); } ); $( function () { rewriteLinks( $( document.body ) ); // Mobile overlays / lazy-loaded sections keep injecting new nodes. var observer = new MutationObserver( function ( mutations ) { mutations.forEach( function ( m ) { m.addedNodes.forEach( function ( node ) { if ( node.nodeType === 1 ) { rewriteLinks( $( node ) ); } } ); } ); } ); observer.observe( document.body, { childList: true, subtree: true } ); } ); // 2. Intercept clicks in the CAPTURE phase, before MobileFrontend's // own delegated handler (which runs in bubble phase) can open // its overlay editor. document.addEventListener( 'click', function ( e ) { var target = e.target.closest ? e.target.closest( EDIT_SELECTOR ) : null; if ( !target || !target.getAttribute( 'href' ) ) { return; } var url = toSubmitUrl( target.getAttribute( 'href' ) ); e.preventDefault(); e.stopImmediatePropagation(); window.location.href = url; }, true ); // true = capture phase, fires before bubble-phase listeners }() ); ru7uisvby1cve1djxe9vcq1qqoj8ms9 6291757 6291732 2026-07-27T23:26:05Z Wikihez 7344 Rûpel hat valakirin 6291757 javascript text/javascript phoiac9h4m842xq45sp7s6u21eteeq1 6291758 6291757 2026-07-27T23:26:38Z Wikihez 7344 Restored revision 6291732 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291758 javascript text/javascript /** * Gadget-ForceWikiEditor.js * Rewrites redlinks and edit buttons/icons to use action=submit, * and pre-empts MobileFrontend's overlay click handler so the * browser navigates to the classic edit form (with WikiEditor) * instead of opening the mobile overlay/VE. */ ( function () { 'use strict'; // Selectors covering redlinks + the various edit entry points // across Minerva/Vector/mobile diff/section-edit UI. var EDIT_SELECTOR = [ 'a.new', // redlinks '.mw-editsection a', // [edit] section links '#ca-edit a', // desktop tab '#ca-ve-edit a', // VE tab if present '.edit-page', // Minerva bottom edit button '.mw-ui-icon-edit', // Minerva pencil icons '.oo-ui-icon-edit', // OOUI edit icon buttons wrapping a link 'a[href*="action=edit"]' // catch-all by href ].join( ',' ); function toSubmitUrl( href ) { if ( !href ) { return href; } try { var url = new URL( href, window.location.origin ); var action = url.searchParams.get( 'action' ); if ( action === 'edit' || !action ) { url.searchParams.set( 'action', 'submit' ); } return url.toString(); } catch ( e ) { return href; } } function rewriteLinks( $context ) { $context.find( EDIT_SELECTOR ).addBack( EDIT_SELECTOR ).each( function () { var $a = $( this ); var href = $a.attr( 'href' ); if ( href ) { $a.attr( 'href', toSubmitUrl( href ) ); } } ); } // 1. Rewrite hrefs whenever content is (re)rendered. mw.hook( 'wikipage.content' ).add( function ( $content ) { rewriteLinks( $content ); } ); $( function () { rewriteLinks( $( document.body ) ); // Mobile overlays / lazy-loaded sections keep injecting new nodes. var observer = new MutationObserver( function ( mutations ) { mutations.forEach( function ( m ) { m.addedNodes.forEach( function ( node ) { if ( node.nodeType === 1 ) { rewriteLinks( $( node ) ); } } ); } ); } ); observer.observe( document.body, { childList: true, subtree: true } ); } ); // 2. Intercept clicks in the CAPTURE phase, before MobileFrontend's // own delegated handler (which runs in bubble phase) can open // its overlay editor. document.addEventListener( 'click', function ( e ) { var target = e.target.closest ? e.target.closest( EDIT_SELECTOR ) : null; if ( !target || !target.getAttribute( 'href' ) ) { return; } var url = toSubmitUrl( target.getAttribute( 'href' ) ); e.preventDefault(); e.stopImmediatePropagation(); window.location.href = url; }, true ); // true = capture phase, fires before bubble-phase listeners }() ); ru7uisvby1cve1djxe9vcq1qqoj8ms9 6291760 6291758 2026-07-27T23:34:15Z Wikihez 7344 6291760 javascript text/javascript ( function () { 'use strict'; var EDIT_SELECTOR = [ 'a.new', '.mw-editsection a', '#ca-edit a', '#ca-ve-edit a', '.edit-page', '.mw-ui-icon-edit', '.oo-ui-icon-edit', 'a[href*="action=edit"]' ].join( ',' ); function isRealEditLink( a ) { var href = a.getAttribute( 'href' ); if ( !href || href.indexOf( 'javascript:' ) === 0 ) { return false; // synthetic links from other gadgets (e.g. aWa's archive controls) } return a.classList.contains( 'new' ) || /[?&]action=edit\b/.test( href ); } function toSubmitUrl( href ) { try { var url = new URL( href, window.location.origin ); var action = url.searchParams.get( 'action' ); if ( action === 'edit' || !action ) { url.searchParams.set( 'action', 'submit' ); } return url.toString(); } catch ( e ) { return href; } } function rewriteLinks( $context ) { $context.find( EDIT_SELECTOR ).addBack( EDIT_SELECTOR ).each( function () { if ( !isRealEditLink( this ) ) { return; } this.setAttribute( 'href', toSubmitUrl( this.getAttribute( 'href' ) ) ); } ); } mw.hook( 'wikipage.content' ).add( function ( $content ) { rewriteLinks( $content ); } ); $( function () { rewriteLinks( $( document.body ) ); var observer = new MutationObserver( function ( mutations ) { mutations.forEach( function ( m ) { m.addedNodes.forEach( function ( node ) { if ( node.nodeType === 1 ) { rewriteLinks( $( node ) ); } } ); } ); } ); observer.observe( document.body, { childList: true, subtree: true } ); } ); document.addEventListener( 'click', function ( e ) { var target = e.target.closest ? e.target.closest( EDIT_SELECTOR ) : null; if ( !target || !isRealEditLink( target ) ) { return; // let it through untouched — e.g. aWa's javascript:void links } var url = toSubmitUrl( target.getAttribute( 'href' ) ); e.preventDefault(); e.stopImmediatePropagation(); window.location.href = url; }, true ); }() ); n08w2j434nkq0q4uwmot630u97dekme 6291764 6291760 2026-07-27T23:36:49Z Wikihez 7344 6291764 javascript text/javascript "use strict"; /*** [ForceWikiEditor]: Force action=submit on redlinks/edit links so WikiEditor loads on mobile ***/ // <nowiki> /*jshint shadow:true, scripturl:true, undef:true, latedef:true, unused:true */ /*global mw, jQuery */ ( function () { var EDIT_SELECTOR = [ 'a.new', // redlinks '.mw-editsection a', // [edit] section links '#ca-edit a', // desktop edit tab '#ca-ve-edit a', // VE tab if present '.edit-page', // Minerva bottom edit button '.mw-ui-icon-edit', // Minerva pencil icons '.oo-ui-icon-edit', // OOUI edit icon buttons 'a[href*="action=edit"]' // catch-all by href ].join( ',' ); // Only treat it as a "real" edit link if it actually points at an edit // action or is a genuine redlink. This deliberately excludes synthetic // links from other gadgets that happen to reuse .mw-editsection for // styling but use javascript:void(...) hrefs with their own click // handlers (e.g. aWa's "arşîv bike" / "betal bike" controls). function isRealEditLink( a ) { var href = a.getAttribute( 'href' ); if ( !href || href.indexOf( 'javascript:' ) === 0 ) { return false; } return a.classList.contains( 'new' ) || /[?&]action=edit\b/.test( href ); } function toSubmitUrl( href ) { try { var url = new URL( href, window.location.origin ); var action = url.searchParams.get( 'action' ); if ( action === 'edit' || !action ) { url.searchParams.set( 'action', 'submit' ); } return url.toString(); } catch ( e ) { return href; } } function rewriteLinks( $context ) { $context.find( EDIT_SELECTOR ).addBack( EDIT_SELECTOR ).each( function () { if ( !isRealEditLink( this ) ) { return; } this.setAttribute( 'href', toSubmitUrl( this.getAttribute( 'href' ) ) ); } ); } // 1. Rewrite hrefs whenever content is (re)rendered. mw.hook( 'wikipage.content' ).add( function ( $content ) { rewriteLinks( $content ); } ); $( function () { rewriteLinks( $( document.body ) ); // Mobile overlays / lazily loaded sections keep injecting new nodes. var observer = new MutationObserver( function ( mutations ) { mutations.forEach( function ( m ) { m.addedNodes.forEach( function ( node ) { if ( node.nodeType === 1 ) { rewriteLinks( $( node ) ); } } ); } ); } ); observer.observe( document.body, { childList: true, subtree: true } ); } ); // 2. Intercept clicks in the CAPTURE phase, before MobileFrontend's own // delegated handler (bubble phase) can open its overlay editor. // isRealEditLink() gating here is what lets other gadgets' synthetic // links (javascript:void hrefs, e.g. aWa's archive controls) pass // through completely untouched. document.addEventListener( 'click', function ( e ) { var target = e.target.closest ? e.target.closest( EDIT_SELECTOR ) : null; if ( !target || !isRealEditLink( target ) ) { return; } var url = toSubmitUrl( target.getAttribute( 'href' ) ); e.preventDefault(); e.stopImmediatePropagation(); window.location.href = url; }, true ); // true = capture phase }() ); // </nowiki> 2aeqlsw3e2iqfjsicce25wypvyphjil 6291803 6291764 2026-07-28T02:44:03Z Wikihez 7344 6291803 javascript text/javascript "use strict"; /*** [ForceWikiEditor]: Force action=submit on redlinks/edit links/buttons so WikiEditor loads on mobile ***/ // <nowiki> /*jshint shadow:true, scripturl:true, undef:true, latedef:true, unused:true */ /*global mw, jQuery */ ( function () { var api = new mw.Api(); var sectionMapPromise = null; // Cache the level-2 section index list for this page (same idea as // Gadget-aWa.js's sectionMapPromise): maps DOM order of top-level // headings to the real section= number MediaWiki expects. function getSectionMap() { if ( !sectionMapPromise ) { sectionMapPromise = api.get( { action: 'parse', page: mw.config.get( 'wgPageName' ), prop: 'sections', formatversion: 2 } ).then( function ( result ) { return result.parse.sections.filter( function ( s ) { return s.level === '2'; } ).map( function ( s ) { return s.index; } ); }, function () { return []; } ); } return sectionMapPromise; } var EDIT_SELECTOR = [ 'a.new', // redlinks '.mw-editsection a', // [edit] section links (desktop-style) '#ca-edit a', // desktop edit tab '#ca-ve-edit a', // VE tab if present '.edit-page', // Minerva page-level edit button '.mw-ui-icon-edit', // Minerva pencil icons '.oo-ui-icon-edit', // OOUI edit icon buttons 'a[href*="action=edit"]' // catch-all by href ].join( ',' ); function findHrefAncestor( el ) { while ( el && el.tagName !== 'A' ) { el = el.parentElement; } return el; } function toSubmitUrl( href ) { try { var url = new URL( href, window.location.origin ); var action = url.searchParams.get( 'action' ); if ( action === 'edit' || !action ) { url.searchParams.set( 'action', 'submit' ); } return url.toString(); } catch ( e ) { return href; } } function buildSubmitUrl( section ) { var params = { title: mw.config.get( 'wgPageName' ), action: 'submit' }; if ( section !== null && section !== undefined ) { params.section = section; } return mw.util.getUrl( null, params ); } // --- 1. Rewrite real hrefs (helps long-press previews / non-JS fallback) --- function rewriteLinks( $context ) { $context.find( EDIT_SELECTOR ).addBack( EDIT_SELECTOR ).each( function () { var anchor = findHrefAncestor( this ); if ( !anchor ) { return; } var href = anchor.getAttribute( 'href' ); if ( !href || href.indexOf( 'javascript:' ) === 0 ) { return; // leave synthetic links (e.g. aWa's archive controls) untouched } if ( anchor.classList.contains( 'new' ) || /[?&]action=edit\b/.test( href ) ) { anchor.setAttribute( 'href', toSubmitUrl( href ) ); } } ); } mw.hook( 'wikipage.content' ).add( function ( $content ) { rewriteLinks( $content ); } ); $( function () { rewriteLinks( $( document.body ) ); var observer = new MutationObserver( function ( mutations ) { mutations.forEach( function ( m ) { m.addedNodes.forEach( function ( node ) { if ( node.nodeType === 1 ) { rewriteLinks( $( node ) ); } } ); } ); } ); observer.observe( document.body, { childList: true, subtree: true } ); } ); // --- 2. Intercept clicks in the capture phase (before MobileFrontend's overlay handler) --- document.addEventListener( 'click', function ( e ) { var matched = e.target.closest ? e.target.closest( EDIT_SELECTOR ) : null; if ( !matched ) { return; } var anchor = findHrefAncestor( matched ); var href = anchor ? anchor.getAttribute( 'href' ) : null; // Synthetic link from another gadget (e.g. aWa's "arşîv bike"): ignore. if ( href && href.indexOf( 'javascript:' ) === 0 ) { return; } // Real href pointing at an edit action or a redlink. if ( href && ( matched.classList.contains( 'new' ) || /[?&]action=edit\b/.test( href ) ) ) { e.preventDefault(); e.stopImmediatePropagation(); window.location.href = toSubmitUrl( href ); return; } // No usable href at all — typical of Minerva's per-section pencil // or floating page-edit button, which exist purely to trigger the // JS overlay. Resolve the target ourselves. if ( !href && ( matched.classList.contains( 'edit-page' ) || matched.classList.contains( 'mw-ui-icon-edit' ) || matched.classList.contains( 'oo-ui-icon-edit' ) || matched.closest( '.mw-editsection' ) ) ) { e.preventDefault(); e.stopImmediatePropagation(); var headingWrap = matched.closest( '.mw-heading' ); if ( !headingWrap ) { // Not tied to any heading → whole-page edit button. window.location.href = buildSubmitUrl(); return; } var allTopHeadings = Array.prototype.slice.call( document.querySelectorAll( '.mw-heading2' ) ); var order = allTopHeadings.indexOf( headingWrap ); if ( order === -1 ) { window.location.href = buildSubmitUrl(); return; } getSectionMap().then( function ( sectionMap ) { var sectionIndex = sectionMap[ order ]; window.location.href = buildSubmitUrl( sectionIndex !== undefined ? sectionIndex : null ); } ); } }, true ); // capture phase }() ); // </nowiki> 3gww5p7cuvux875w61aul3ilvn3wkin Bikarhêner:Wikihez/Gadget-start.js 2 974484 6291636 6291628 2026-07-27T12:43:58Z Wikihez 7344 6291636 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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 (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append($("<br>")).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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 (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append($("<br>")).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys, "Zarava hilbijêre"); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append($("<br>")).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava), "Zarava hilbijêre"); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 1akb5ghknc15ou7rkzo70xmh0fve4vp 6291637 6291636 2026-07-27T12:48:37Z Wikihez 7344 6291637 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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 (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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 (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys, "Zarava hilbijêre"); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append($("<br>")).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava), "Zarava hilbijêre"); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> ohou3hf10liiyodrd94z6t791ev6fgu 6291638 6291637 2026-07-27T13:01:26Z Wikihez 7344 6291638 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys, "Zarava hilbijêre"); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append($("<br>")).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava), "Zarava hilbijêre"); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> hqbuf4cgi04fxb953lal3l0xqhqnskz 6291645 6291638 2026-07-27T13:16:05Z Wikihez 7344 6291645 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName, placeholder) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: placeholder, 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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", "Kelîme…"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 8f5s07d3n5fvzv6dqxderll38beedsn 6291647 6291645 2026-07-27T13:21:09Z Wikihez 7344 Restored revision 6291638 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291647 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys, "Zarava hilbijêre"); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append($("<br>")).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava), "Zarava hilbijêre"); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> hqbuf4cgi04fxb953lal3l0xqhqnskz 6291648 6291647 2026-07-27T13:22:10Z Wikihez 7344 Restored revision 6291645 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291648 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName, placeholder) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: placeholder, 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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", "Kelîme…"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 8f5s07d3n5fvzv6dqxderll38beedsn 6291649 6291648 2026-07-27T13:23:31Z Wikihez 7344 6291649 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); tplTitleInput.show().focus(); } else { dfnArea.show(); tplTitleInput.hide().val(""); } updateFieldVisibility(); // 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, step.question_fmt))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 9b2vmasx1k5q692skg0d29cga9a8xz2 6291679 6291649 2026-07-27T18:14:55Z Wikihez 7344 6291679 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into werger+îzah instead // (see buildSenseBlock's updateManeMode), so that sentence would // be misleading there. question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Werger + Îzah boxes (non-ku alternative to the plain mane box) — // For entries in any language other than ku, editors don't write a // Kurdish-style gloss directly — they give a direct Kurdish // translation of the term, plus an explanatory gloss wrapped in // {{îzah|…}}. Rather than teach getSenses()/getOutput()/linkify a // second data shape, these two boxes just write their combined // text into dfnArea (and re-fire its "input" event), so dfnArea // stays the single source of truth for every existing consumer — // this pair is purely a front-end convenience over it. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Wergera rasterast a kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Şirove (îzah) binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty if (dfn) { dfn = stripWikilinks(dfn); if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } else { dfn = "{{mane?|" + lang + "}}"; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(restoreCites(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(restoreCites(linked)); }); } else { callback(restoreCites(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). // Falls back to putting everything in werger if there's no {{îzah|…}}. var maneParts = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(sense.mane || ""); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts[1] : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts[2] : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> cb9v9alqsl5j9xnbduj5szwoyw7nwsn 6291682 6291679 2026-07-27T18:31:10Z Wikihez 7344 6291682 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } // Splits a mane string produced by the non-ku werger+îzah boxes (see // buildSenseBlock's syncNonKuToMane) back into its parts. Returns null // for anything that doesn't end in a {{îzah|…}} call — a plain ku mane, // or a non-ku sense where the îzah box was left empty. function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } // Sentinel markers standing in for {{îzah|…}} while its gloss text // passes through linkify. wiktviLinkify treats {{…}} template calls as // opaque and never links inside them — that's why îzah text embedded // directly in braces was never getting wikilinked. getOutput() wraps // the raw gloss in these markers instead of the real braces, lets it // through linkify like any other definition text, then swaps the // markers back for the actual {{îzah|…}} call via restoreIzah() once // the enclosed text has been linkified. var IZAH_MARK_START = "\u2060WIKTKU-IZAH-START\u2060"; var IZAH_MARK_END = "\u2060WIKTKU-IZAH-END\u2060"; var IZAH_MARK_RE = new RegExp( escapeRegExp(IZAH_MARK_START) + "([\\s\\S]*?)" + escapeRegExp(IZAH_MARK_END), "g"); function restoreIzah(t) { return t.replace(IZAH_MARK_RE, function (_, content) { return "{{îzah|" + content + "}}"; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into werger+îzah instead // (see buildSenseBlock's updateManeMode), so that sentence would // be misleading there. question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Werger + Îzah boxes (non-ku alternative to the plain mane box) — // For entries in any language other than ku, editors don't write a // Kurdish-style gloss directly — they give a direct Kurdish // translation of the term, plus an explanatory gloss wrapped in // {{îzah|…}}. Rather than teach getSenses()/getOutput()/linkify a // second data shape, these two boxes just write their combined // text into dfnArea (and re-fire its "input" event), so dfnArea // stays the single source of truth for every existing consumer — // this pair is purely a front-end convenience over it. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Wergera rasterast a kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Şirove (îzah) binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string so it can be linkified via markers (see restoreIzah) // instead of being sent through linkify still wrapped in the // literal {{îzah|…}} braces, which would never get linked. var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; // Îzah gloss, marker-wrapped so it passes through linkify like // any other definition text (see IZAH_MARK_START/restoreIzah). if (izahRaw !== null && $.trim(izahRaw) !== "") { out += (dfn ? " " : "") + IZAH_MARK_START + izahRaw + IZAH_MARK_END; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block, and // swap any îzah markers back for the real {{îzah|…}} template // call (restoreIzah) — order between the two doesn't matter, // their token patterns never overlap. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } function finalize(t) { return restoreIzah(restoreCites(t)); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(finalize(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(finalize(linked)); }); } else { // Linkify module unavailable — îzah markers must still be // swapped back to {{îzah|…}}, or they'd leak into the // saved wikitext verbatim. callback(finalize(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 9u34sxf435gy6ul400ub6uuvdgl2k9t 6291683 6291682 2026-07-27T18:36:19Z Wikihez 7344 6291683 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } // Splits a mane string produced by the non-ku werger+îzah boxes (see // buildSenseBlock's syncNonKuToMane) back into its parts. Returns null // for anything that doesn't end in a {{îzah|…}} call — a plain ku mane, // or a non-ku sense where the îzah box was left empty. function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } // Sentinel markers standing in for {{îzah|…}} while its gloss text // passes through linkify. wiktviLinkify treats {{…}} template calls as // opaque and never links inside them — that's why îzah text embedded // directly in braces was never getting wikilinked. getOutput() wraps // the raw gloss in these markers instead of the real braces, lets it // through linkify like any other definition text, then swaps the // markers back for the actual {{îzah|…}} call via restoreIzah() once // the enclosed text has been linkified. // // These must contain NO letters: linkify wikilinks any run of letters // it finds regardless of whether it's a real dictionary word — an // earlier version used "WIKTKU-IZAH-START" and linkify happily wrapped // "WIKTKU", "IZAH" and "START" individually as if they were entries. // Private-Use-Area codepoints (category Co) aren't letters in any // script, so a letter-run regex has no reason to ever match them — // they pass straight through untouched, same as a space or a digit. var IZAH_MARK_START = "\uE000\uE001\uE002\uE003"; var IZAH_MARK_END = "\uE004\uE005\uE006\uE007"; var IZAH_MARK_RE = new RegExp( escapeRegExp(IZAH_MARK_START) + "([\\s\\S]*?)" + escapeRegExp(IZAH_MARK_END), "g"); function restoreIzah(t) { return t.replace(IZAH_MARK_RE, function (_, content) { return "{{îzah|" + content + "}}"; }); } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into werger+îzah instead // (see buildSenseBlock's updateManeMode), so that sentence would // be misleading there. question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Werger + Îzah boxes (non-ku alternative to the plain mane box) — // For entries in any language other than ku, editors don't write a // Kurdish-style gloss directly — they give a direct Kurdish // translation of the term, plus an explanatory gloss wrapped in // {{îzah|…}}. Rather than teach getSenses()/getOutput()/linkify a // second data shape, these two boxes just write their combined // text into dfnArea (and re-fire its "input" event), so dfnArea // stays the single source of truth for every existing consumer — // this pair is purely a front-end convenience over it. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Wergera rasterast a kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Şirove (îzah) binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string so it can be linkified via markers (see restoreIzah) // instead of being sent through linkify still wrapped in the // literal {{îzah|…}} braces, which would never get linked. var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; // Îzah gloss, marker-wrapped so it passes through linkify like // any other definition text (see IZAH_MARK_START/restoreIzah). if (izahRaw !== null && $.trim(izahRaw) !== "") { out += (dfn ? " " : "") + IZAH_MARK_START + izahRaw + IZAH_MARK_END; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); var idx = defLines.length; defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block, and // swap any îzah markers back for the real {{îzah|…}} template // call (restoreIzah) — order between the two doesn't matter, // their token patterns never overlap. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } function finalize(t) { return restoreIzah(restoreCites(t)); } var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no linkify needed. callback(finalize(text)); return; } var didTryToLoad = function () { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(text, function (linked) { callback(finalize(linked)); }); } else { // Linkify module unavailable — îzah markers must still be // swapped back to {{îzah|…}}, or they'd leak into the // saved wikitext verbatim. callback(finalize(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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> m70wg11itbgixevhoje22uwpxk723ue 6291688 6291683 2026-07-27T18:42:51Z Wikihez 7344 6291688 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); // Kick off both metadata API requests as early as possible, needing only // the mediawiki.api module rather than waiting for jquery.chosen and // oojs-ui-core too (those are only needed later, to actually build the // form). mediawiki.api is used all over the wiki, so this resolves // near-instantly in practice — but we still wait for it properly rather // than assuming mw.Api is already defined. The jquery.chosen/oojs-ui-core // load happens in parallel with this, further down. var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } // Regex source for a "== {{ziman|CODE}} ==" header, tolerant of extra // whitespace. codePattern: escaped code for one language, or "[^}]+" for any. function langHeaderSource(codePattern) { return "==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } // Finds a language's header in wikitext (see langHeaderSource). Returns // { index, match } or null. function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } // Splits a mane string produced by the non-ku werger+îzah boxes (see // buildSenseBlock's syncNonKuToMane) back into its parts. Returns null // for anything that doesn't end in a {{îzah|…}} call — a plain ku mane, // or a non-ku sense where the îzah box was left empty. function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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; } // Members of [[Kategorî:Çavkanî]] (source/citation templates), used by the // "Ji Kategorî:Çavkanî şablonekê hilbijêre" jêder-source option. Fetched // once on first use and cached — every citation row's picker shares it. var catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); // Draft cache for this page — lets the editor manually save/restore the // whole wizard state (shared lang/pron + every section) via // [[MediaWiki:Gadget-StorageUtils.js]]'s ObjectStorage, independent of // any single browser session. Keyed per page so different articles' // drafts don't collide. var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); // Mobile detection: MobileFrontend sets wgMFMode, or fall back to touch check. var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; // ---- Searchable picker -------------------------------------------------- // Every dropdown in this form -- desktop and mobile alike -- uses the // wrapNativeSelect() widget further down. jquery.chosen used to fill this // role on desktop, but it renders search results in plain option order and // offers no hook for re-ranking them, so it could never put an exact code // match ("ang" -> "Îngilîziya kevn") above the substring matches. It is no // longer loaded or referenced anywhere. // ---- Diacritic-insensitive search -------------------------------------- // Lets "ingilizi" find "Îngilîzî", "kurdi" find "Kurdî", "sopani" // find "Şopanî". NFD decomposition handles every letter written as // base + combining accent (î ê û ç ş á é ö ...); // FOLD_EXTRA covers the handful Unicode cannot decompose that way. var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } /** * Replaces a native <select> with a searchable text input + ranked result * list. Returns a wrapper element containing the original (hidden) select, * so every call-site that reads .val() or listens for "change" on the * select keeps working unchanged. * * After changing the option list, trigger "wiktku:refresh" on the select so * the widget re-reads its <option>s. */ function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); // Multi-selects aren't supported by this widget, and a native multiple // <select> is perfectly usable as-is -- leave it alone. if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; // Hide the native select -- we drive it programmatically. select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); // Full option cache -- rebuilt when wiktku:refresh fires. var allOptions = []; // Options currently rendered, in display order, plus the keyboard cursor. var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); // Multi-word fallback (Chosen's enable_split_word_search): keep // anything whose label contains every token, e.g. "kevn ing". if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full // list -- the behaviour Chosen had on desktop. this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; // Zaravayên kurdî yên ku di beşa "Bi zaravayên din" de tên pêşkêşkirin — // ev kod ji beşa Werger têne derxistin daku heman zimên du caran neyê xwendin. var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense, since a // template-based sense has no "own" gloss for alternate forms, synonyms, // antonyms, coordinate terms, hypernyms or hyponyms to attach to. Etîket, // Nimûne and Jêgirtin stay visible either way. var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{" + templateName + "|" + lang + "|" + words[0] + "}}\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 + "|" + 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"; } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonê lê bigere"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity — 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "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", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into werger+îzah instead // (see buildSenseBlock's updateManeMode), so that sentence would // be misleading there. question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Werger + Îzah boxes (non-ku alternative to the plain mane box) — // For entries in any language other than ku, editors don't write a // Kurdish-style gloss directly — they give a direct Kurdish // translation of the term, plus an explanatory gloss wrapped in // {{îzah|…}}. Rather than teach getSenses()/getOutput()/linkify a // second data shape, these two boxes just write their combined // text into dfnArea (and re-fire its "input" event), so dfnArea // stays the single source of truth for every existing consumer — // this pair is purely a front-end convenience over it. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Wergera rasterast a kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Şirove (îzah) binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; 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 ji aliyê etîmolojiyê ve 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 7is862alnrc59pccllrfwc0734v48bx 6291692 6291688 2026-07-27T19:39:25Z Wikihez 7344 6291692 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // wiktku:refresh -> re-cache the option list. Fired after ziman.json // loads, after options are enabled/disabled, and after programmatic // .val() changes. "chosen:updated" is kept as a legacy alias in case // another gadget still fires the old Chosen event at these selects. select.on("wiktku:refresh chosen:updated", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a plain {code: label} object (the format used for langChoices // and posChoices in data.json) into the ordered array of choice objects // ({code, label[, sortKey]}) that the rest of this script works with. // isLang: true adds a sortKey (defaults to label) and tells populateMenus // to show "(code)" after the label — used for language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs leave // choice.code/choice.label undefined, so Chosen (desktop) ends up // with unusable options. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // For entries in any language other than ku, editors don't write a // Kurdish-style gloss directly — they give a direct Kurdish // translation of the term, plus an explanatory gloss wrapped in // {{îzah|…}}. Rather than teach getSenses()/getOutput()/linkify a // second data shape, these two boxes just write their combined // text into dfnArea (and re-fire its "input" event), so dfnArea // stays the single source of truth for every existing consumer — // this pair is purely a front-end convenience over it. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Notify Chosen (desktop) / the search widget (mobile) that the // option list has changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets the // searchable picker (or Chosen, if useNativePicker is turned off). initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> r9b7zc6glzvx6ker85xfj7hqi5wzhiq 6291695 6291692 2026-07-27T20:10:34Z Wikihez 7344 6291695 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> pb58f3afnyrkcd66fgwqap2a2tw22y1 6291696 6291695 2026-07-27T20:12:14Z Wikihez 7344 6291696 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 3orqwcbktfokhr4bogeiij3vfpj1y2z 6291701 6291696 2026-07-27T20:22:27Z Wikihez 7344 6291701 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; // Word-list steps that get the tighter "compact" step layout — see // .wiktku-start-step-compact in styles.css. steps.je.compact = true; steps.tekildar.compact = true; steps.binereherwiha.compact = true; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#wpTextbox1").val(wikitext); } $("html, body").animate({scrollTop: 0}); callToAction.text("Hindik ma!"); $("#wiktku-preview-container").remove(); destroy(); }); }); // Steps rendered side by side in a shared row instead of stacking full // width — each keeps its own #wiktku-start-<id> div and behavior // unchanged, only its parent element differs, so refresh()'s per-id // slideUp/slideDown and every other id-based lookup still just work. var STEP_ROW_GROUPS = { lang: "lang-pron", pron: "lang-pron", pos: "pos-extras", cinsiyet: "pos-extras", lektur: "pos-extras", tr: "pos-extras" }; var openRows = {}; $.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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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(); if (step.compact) stepDiv.addClass("wiktku-start-step-compact"); // Insert tab bar just before the first per-section step. if (step.id === "pos") startForm.append(sectionTabsDiv); var rowKey = STEP_ROW_GROUPS[step.id]; if (rowKey) { if (!openRows[rowKey]) { openRows[rowKey] = $("<div class='wiktku-start-step-row'></div>") .addClass("wiktku-row-" + rowKey); startForm.append(openRows[rowKey]); } stepDiv.addClass("wiktku-start-step-grouped"); openRows[rowKey].append(stepDiv); } else { startForm.append(stepDiv); } }); // ── Section tab helpers ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> gu3lzchlgr4ovqq3gf2iseqdemr6pvj 6291703 6291701 2026-07-27T20:24:55Z Wikihez 7344 Restored revision 6291696 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291703 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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 (citation) group — growing list, same structure as Nimûne. — (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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 3orqwcbktfokhr4bogeiij3vfpj1y2z 6291715 6291703 2026-07-27T20:53:42Z Wikihez 7344 6291715 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": "); 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": ") .append($("<span></span>").addClass("wiktku-dfn-sublabel-hint").text(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 (citation) group — growing list, same structure as Nimûne. — (function () { var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group"); var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text("Jêgirtin")) .append(": "); 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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> cpqlghrl1hyhy17q5zpv4guxrpwktok 6291717 6291715 2026-07-27T21:03:54Z Wikihez 7344 6291717 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": "); 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": ") .append($("<span></span>").addClass("wiktku-dfn-sublabel-hint").text(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 (citation) group — growing list, same structure as Nimûne. — (function () { var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group"); var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text("Jêgirtin")) .append(": "); 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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // True only when at least one sense has a regular mane (needs linkify). var hasRegularMane = senses.some(function (s) { return !s.tpl && s.mane !== ""; }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } if (!hasRegularMane) { // All filled senses are template senses — no îzah is possible // either, so there's nothing here that needs linkify at all. callback(restoreCites(text)); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = mainLinked.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); continueBtn.$element.addClass("wiktku-btn-sending"); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { // Immediate, unmissable feedback that the click registered — // the mw.notify toast alone is easy to miss, and the button's // disabled state (set later, inside the submit handler once // getWikitext resolves) can take a moment to kick in. continueBtn.$element.addClass("wiktku-btn-flash"); setTimeout(function () { continueBtn.$element.removeClass("wiktku-btn-flash"); }, 500); continueBtn.setLabel("Tê şandin…"); mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> o3d1q664kf04w6scxq7oy4w5k205g3s 6291819 6291717 2026-07-28T06:18:42Z Wikihez 7344 6291819 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); var combined = w; if (iz) combined += (combined ? " " : "") + "{{îzah|" + iz + "}}"; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": "); 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": ") .append($("<span></span>").addClass("wiktku-dfn-sublabel-hint").text(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 (citation) group — growing list, same structure as Nimûne. — (function () { var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group"); var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text("Jêgirtin")) .append(": "); 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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense // True only once some sense's *actual* dfn text (post werger/îzah // split) is non-empty. A non-ku sense with werger left blank and // only îzah filled in has sense.mane === "{{îzah|…}}", which is // truthy, but splits down to an empty dfn — so it must NOT count // here. Sending a "# {{wiktku-izah-N}}" line (a bare template // call with no plain words at all) through the main linkify pass // is what makes the linkify gadget hang, since it has nothing to // word-link on that line. Skipping the main pass in that case is // what fixes the freeze. var hasLinkableMane = false; $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } if (dfn) hasLinkableMane = true; var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } // Runs the îzah-only linkify pass against `base` (either the raw // text, when there's no linkable mane to run the main pass on // first, or the already-linkified main text). Shared by both // branches below so the token-splice logic only lives once. function runIzahPass(base) { var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = base.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); } if (!hasLinkableMane) { if (!hasIzah) { // All filled senses are template senses (or otherwise have // no plain text at all) — nothing here needs linkify. callback(restoreCites(text)); return; } // There's no plain mane text anywhere (e.g. werger left blank // with only îzah filled in), so every defLine is just a bare // template call with nothing to word-link. Sending a line // like "# {{wiktku-izah-0}}" through the main linkify pass // gives it no plain words to work with, which is what made // the gadget hang — so skip that pass entirely and run only // the îzah pass, splicing straight into the unlinkified text. var loadIzahOnly = function () { runIzahPass(text); }; mw.loader.using("ext.gadget.linkify", loadIzahOnly, loadIzahOnly); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. runIzahPass(mainLinked); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder, // Only when a regular sense has content (real mane, or {{mane?}} // with other fields filled in) — a şablon sense never counts. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (!hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); continueBtn.$element.addClass("wiktku-btn-sending"); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { // Immediate, unmissable feedback that the click registered — // the mw.notify toast alone is easy to miss, and the button's // disabled state (set later, inside the submit handler once // getWikitext resolves) can take a moment to kick in. continueBtn.$element.addClass("wiktku-btn-flash"); setTimeout(function () { continueBtn.$element.removeClass("wiktku-btn-flash"); }, 500); continueBtn.setLabel("Tê şandin…"); mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> 28ukicgut6blib8l74y8qgwym692q0m 6291820 6291819 2026-07-28T06:39:14Z Wikihez 7344 6291820 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); // {{îzah|…}} only makes sense as an addendum to an actual // translation — if werger is left blank, there's nothing for // it to clarify, so just use the îzah text as the definition // itself instead of wrapping it in a now-pointless template. var combined = w ? (iz ? w + " {{îzah|" + iz + "}}" : w) : iz; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": "); 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": ") .append($("<span></span>").addClass("wiktku-dfn-sublabel-hint").text(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 (citation) group — growing list, same structure as Nimûne. — (function () { var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group"); var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text("Jêgirtin")) .append(": "); 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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense // True only once some sense's *actual* dfn text (post werger/îzah // split) is non-empty. A non-ku sense with werger left blank and // only îzah filled in has sense.mane === "{{îzah|…}}", which is // truthy, but splits down to an empty dfn — so it must NOT count // here. Sending a "# {{wiktku-izah-N}}" line (a bare template // call with no plain words at all) through the main linkify pass // is what makes the linkify gadget hang, since it has nothing to // word-link on that line. Skipping the main pass in that case is // what fixes the freeze. var hasLinkableMane = false; $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } if (dfn) hasLinkableMane = true; var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } // Runs the îzah-only linkify pass against `base` (either the raw // text, when there's no linkable mane to run the main pass on // first, or the already-linkified main text). Shared by both // branches below so the token-splice logic only lives once. function runIzahPass(base) { var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = base.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); } if (!hasLinkableMane) { if (!hasIzah) { // All filled senses are template senses (or otherwise have // no plain text at all) — nothing here needs linkify. callback(restoreCites(text)); return; } // There's no plain mane text anywhere (e.g. werger left blank // with only îzah filled in), so every defLine is just a bare // template call with nothing to word-link. Sending a line // like "# {{wiktku-izah-0}}" through the main linkify pass // gives it no plain words to work with, which is what made // the gadget hang — so skip that pass entirely and run only // the îzah pass, splicing straight into the unlinkified text. var loadIzahOnly = function () { runIzahPass(text); }; mw.loader.using("ext.gadget.linkify", loadIzahOnly, loadIzahOnly); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. runIzahPass(mainLinked); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder. // Skip it only when every filled sense is a şablon sense (the // template covers this already); a completely empty entry with // no şablon chosen still gets the placeholder, same as before // dfn had any content at all. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasFilledTplSense = dfnSenses.some(function (s) { return !!s.tpl && !!s.tplTitle; }); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (hasFilledTplSense && !hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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 ""; // A completely empty entry (nothing filled in dfn at all, no // şablon chosen either) still gets a placeholder Werger section // to fill in later — same reasoning as Etîmolojî's {{ji?}}. Only // skip an individual placeholder gloss below when some other // sense actually has real content, making that particular // placeholder redundant. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); // 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. If some other sense already has real // content, this placeholder is redundant — skip it. If the // whole entry is empty, keep it so Werger still gets a // section to fill in. if (!gloss.text && !rows.length && hasRegularMane) 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); continueBtn.$element.addClass("wiktku-btn-sending"); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { // Immediate, unmissable feedback that the click registered — // the mw.notify toast alone is easy to miss, and the button's // disabled state (set later, inside the submit handler once // getWikitext resolves) can take a moment to kick in. continueBtn.$element.addClass("wiktku-btn-flash"); setTimeout(function () { continueBtn.$element.removeClass("wiktku-btn-flash"); }, 500); continueBtn.setLabel("Tê şandin…"); mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> fwjztpm2p9mytkjgl7d2kaf9g0c2icv 6291821 6291820 2026-07-28T06:48:48Z Wikihez 7344 6291821 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); // {{îzah|…}} only makes sense as an addendum to an actual // translation — if werger is left blank, there's nothing for // it to clarify, so just use the îzah text as the definition // itself instead of wrapping it in a now-pointless template. var combined = w ? (iz ? w + " {{îzah|" + iz + "}}" : w) : iz; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": "); 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": ") .append($("<span></span>").addClass("wiktku-dfn-sublabel-hint").text(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 (citation) group — growing list, same structure as Nimûne. — (function () { var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group"); var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text("Jêgirtin")) .append(": "); 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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense // True only once some sense's *actual* dfn text (post werger/îzah // split) is non-empty. A non-ku sense with werger left blank and // only îzah filled in has sense.mane === "{{îzah|…}}", which is // truthy, but splits down to an empty dfn — so it must NOT count // here. Sending a "# {{wiktku-izah-N}}" line (a bare template // call with no plain words at all) through the main linkify pass // is what makes the linkify gadget hang, since it has nothing to // word-link on that line. Skipping the main pass in that case is // what fixes the freeze. var hasLinkableMane = false; $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } if (dfn) hasLinkableMane = true; var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } // Runs the îzah-only linkify pass against `base` (either the raw // text, when there's no linkable mane to run the main pass on // first, or the already-linkified main text). Shared by both // branches below so the token-splice logic only lives once. function runIzahPass(base) { var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = base.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); } if (!hasLinkableMane) { if (!hasIzah) { // All filled senses are template senses (or otherwise have // no plain text at all) — nothing here needs linkify. callback(restoreCites(text)); return; } // There's no plain mane text anywhere (e.g. werger left blank // with only îzah filled in), so every defLine is just a bare // template call with nothing to word-link. Sending a line // like "# {{wiktku-izah-0}}" through the main linkify pass // gives it no plain words to work with, which is what made // the gadget hang — so skip that pass entirely and run only // the îzah pass, splicing straight into the unlinkified text. var loadIzahOnly = function () { runIzahPass(text); }; mw.loader.using("ext.gadget.linkify", loadIzahOnly, loadIzahOnly); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. runIzahPass(mainLinked); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder. // Skip it only when every filled sense is a şablon sense (the // template covers this already); a completely empty entry with // no şablon chosen still gets the placeholder, same as before // dfn had any content at all. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasFilledTplSense = dfnSenses.some(function (s) { return !!s.tpl && !!s.tplTitle; }); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (hasFilledTplSense && !hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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 ""; // A completely empty entry (nothing filled in dfn at all, no // şablon chosen either) still gets a placeholder Werger section // to fill in later — same reasoning as Etîmolojî's {{ji?}}. Only // skip an individual placeholder gloss below when some other // sense actually has real content, making that particular // placeholder redundant. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); // 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. If some other sense already has real // content, this placeholder is redundant — skip it. If the // whole entry is empty, keep it so Werger still gets a // section to fill in. if (!gloss.text && !rows.length && hasRegularMane) 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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) { // wrapNativeSelect() hides the real <select> and shows a // proxy search box in its place, so focusing `input` // directly (the hidden select) does nothing visible and // browsers won't scroll to it -- that's why the step // looked "invisible" and had to be found by scrolling. // Focus whichever of the two is actually on screen. var focusTarget = input.is(":visible") ? input : input.closest(".wiktku-native-select-wrap").find(".wiktku-ac-input"); if (!focusTarget.length) focusTarget = input; // Belt-and-suspenders: explicitly scroll the step into // view rather than relying on focus()'s scroll-into-view // behaviour, which mobile browsers apply inconsistently // right after a slideDown animation. var stepEl = stepDiv.get(0); if (stepEl && typeof stepEl.scrollIntoView === "function") { stepEl.scrollIntoView({ behavior: "smooth", block: "start" }); } focusTarget.focus(); }; didFocus = true; } stepDiv.slideDown(didSlideDown); } if (step.required && (values[stepId] === "" || (step.multiple && values[stepId].join("") === ""))) { canContinue = false; } }); continueBtn.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); continueBtn.$element.addClass("wiktku-btn-sending"); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { // Immediate, unmissable feedback that the click registered — // the mw.notify toast alone is easy to miss, and the button's // disabled state (set later, inside the submit handler once // getWikitext resolves) can take a moment to kick in. continueBtn.$element.addClass("wiktku-btn-flash"); setTimeout(function () { continueBtn.$element.removeClass("wiktku-btn-flash"); }, 500); continueBtn.setLabel("Tê şandin…"); mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> m0kphpcupv9krw6h7hkf6m4dygyozx0 6291823 6291821 2026-07-28T07:29:15Z Wikihez 7344 6291823 javascript text/javascript // Li ser [[vi:MediaWiki:Gadget-start.js]] hatiye refaktorkirin. // implicit dependencies: StorageUtils (ObjectStorage) //<nowiki> $(function () { if (window.location.href.includes("editintro=User:Wikihez/creation/intro")) { return; // Do not run the script wextê WF:Bilez dişuxile } var ns = mw.config.get("wgNamespaceNumber"); if (ns && !(ns === 2 && mw.config.get("wgPageName").match(/\/ceribandin$|\/test$/))) { return; } var action = mw.config.get("wgAction"); var pageExists = !!mw.config.get("wgArticleId"); var addLangMode = pageExists && mw.util.getParamValue("wiktkuaddlang") === "1"; if (action === "view" && pageExists) { var targetContainer; var skin = mw.config.get('skin'); if (skin === 'vector-2022') { targetContainer = 'p-cactions'; } else if (skin === 'vector') { targetContainer = 'p-tb'; } else { targetContainer = 'p-views'; } mw.util.addPortletLink(targetContainer, mw.util.getUrl(mw.config.get("wgPageName"), { action: "submit", wiktkuaddlang: "1" }), "+Ziman/beşeke din", "ca-wiktku-addlang", "Ji vê rûpelê re ziman an jî beşeke nû zêde bike"); return; } if (!(action === "edit" || action === "submit")) { return; } if (!addLangMode && !$(".mw-newarticletext, .mw-newarticletextanon").length) { return; } mw.notify( "Amûr dest pê dike, hinek bisekinin.\nNot: jkx Sentaks (Syntax highlighting) neaktîv bikin", { type: "info", tag: "wiktku-start-notice", autoHide: true, autoHideSeconds: 10 } ); var dataJsonPromise, zimanJsonPromise; var metaApiPromise = mw.loader.using("mediawiki.api").then(function () { var metaApi = new mw.Api(); dataJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-start.js/data.json", rvprop: "content", rvslots: "main", formatversion: 2 }); zimanJsonPromise = metaApi.get({ action: "query", prop: "revisions", titles: "MediaWiki:Gadget-translation_editor.js/ziman.json", rvprop: "content", rvslots: "main", formatversion: 2 }); return dataJsonPromise; }); function capitalize(str) { if (!str) return str; return str[0].toUpperCase() + str.substr(1); } function decapitalize(str) { if (!str) return str; return str[0].toLowerCase() + str.substr(1); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function langHeaderSource(codePattern) { return "\n?==\\s*\\{\\{\\s*ziman\\s*\\|\\s*(" + codePattern + ")\\s*\\}\\}\\s*=="; } function findLangHeader(text, code) { var m = new RegExp(langHeaderSource(escapeRegExp(code))).exec(text); return m ? { index: m.index, match: m[0] } : null; } function stripWikilinks(str) { return str.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, function (m, target, display) { return display || target; }); } function splitWergerIzah(mane) { var m = /^([\s\S]*?)\s*\{\{îzah\|([\s\S]*)\}\}\s*$/.exec(mane || ""); return m ? { werger: m[1], izah: m[2] } : null; } 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 catSrcTemplates = null; var catSrcTemplatesPromise = null; function fetchCatSrcTemplates() { if (catSrcTemplatesPromise) return catSrcTemplatesPromise; catSrcTemplatesPromise = new mw.Api().get({ action: "query", list: "categorymembers", cmtitle: "Kategorî:Çavkanî", cmnamespace: 10, cmlimit: "max", formatversion: 2 }).then(function (data) { var members = (data.query && data.query.categorymembers) || []; catSrcTemplates = $.map(members, function (m) { // Pêşgira navî ya "Şablon:" rake. return m.title.replace(/^[^:]+:/, ""); }); catSrcTemplates.sort(function (a, b) { return a.localeCompare(b, userLang); }); return catSrcTemplates; }, function () { catSrcTemplates = []; return catSrcTemplates; }); return catSrcTemplatesPromise; } var pageName = mw.config.get("wgPageName").replaceAll(/_/g, " "); if (ns) pageName = pageName.replace(/.*\//, ""); var pageNameRe = escapeRegExp(pageName); var userLang = mw.config.get("wgUserLanguage"); var formCache = new ObjectStorage("wiktku_start_draft_" + mw.config.get("wgPageName"), 1); var isMobile = !!mw.config.get("wgMFMode") || window.matchMedia("(pointer: coarse)").matches; var FOLD_EXTRA = { "ı": "i", // dotless i "ø": "o", // o with stroke "đ": "d", // d with stroke "ð": "d", // eth "ə": "e", // schwa "ħ": "h", // h with stroke "ł": "l", // l with stroke "ŋ": "n", // eng "ʉ": "u", // u bar "ɨ": "i", // i bar "ʒ": "z", // ezh "ɛ": "e", // open e "ɔ": "o", // open o "æ": "ae", "œ": "oe", "ß": "ss", "þ": "th" }; function foldDiacritics(str) { if (str === null || str === undefined) return ""; var s = String(str).toLowerCase(); if (typeof s.normalize === "function") { // Split "î" into "i" + combining circumflex, then drop the accent. s = s.normalize("NFD").replace(/[\u0300-\u036f]/g, ""); } return s.replace(/[^\u0000-\u007f]/g, function (ch) { return Object.prototype.hasOwnProperty.call(FOLD_EXTRA, ch) ? FOLD_EXTRA[ch] : ch; }); } function wrapNativeSelect(select) { var wrapper = $("<span class='wiktku-native-select-wrap'></span>"); if (select.prop("multiple")) { return wrapper.append(select); } var placeholder = select.attr("data-placeholder") || "Le bigere..."; select.hide(); var textInput = $("<input type='search' autocomplete='off'>") .attr("placeholder", placeholder) .attr("role", "combobox") .attr("aria-autocomplete", "list") .attr("aria-expanded", "false") .addClass("wiktku-start-narrow wiktku-ac-input"); var resultsList = $("<ul class='wiktku-ac-results' role='listbox'></ul>").hide(); var allOptions = []; var shown = []; var activeIndex = -1; function cacheOptions() { allOptions = []; select.find("option").each(function () { var v = $(this).val(); if (!v) return; // skip the empty placeholder option var text = $(this).text(); // Language options read "Name (code)" -- score the name on its own // so the trailing code doesn't also count as a name match. var name = text.replace(/\s*\([^()]*\)\s*$/, ""); allOptions.push({ value: v, text: text, disabled: $(this).prop("disabled"), foldCode: foldDiacritics(v), foldName: foldDiacritics(name), foldText: foldDiacritics(text) }); }); } cacheOptions(); // True if `q` starts a word inside `name` ("kevn" in "ingiliziya kevn"). function startsWord(name, q) { var from = 0, at; while ((at = name.indexOf(q, from)) !== -1) { if (at === 0 || /[\s\-\u2013\u2014(/,.]/.test(name.charAt(at - 1))) return true; from = at + 1; } return false; } // Lower rank = better match. This is the whole point of the widget: a // code that *is* the query, or begins with it, always outranks a name // that merely contains it -- so "ang" lists "Îngilîziya kevn (ang)" // first instead of burying it among every name containing "ang". var RANK_NONE = 99; function rankOption(o, q) { var code = o.foldCode, name = o.foldName; if (code === q) return 0; // exact code if (code.indexOf(q) === 0) return 1; // code prefix if (name === q) return 2; // exact name if (name.indexOf(q) === 0) return 3; // name prefix if (startsWord(name, q)) return 4; // starts a word in the name if (name.indexOf(q) !== -1) return 5; // name substring if (code.indexOf(q) !== -1) return 6; // code substring if (o.foldText.indexOf(q) !== -1) return 7; // anywhere else in the label return RANK_NONE; } function positionList() { // Position the list above or below depending on 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%" }); } function closeList() { resultsList.hide(); textInput.attr("aria-expanded", "false"); activeIndex = -1; } function showResults(query) { var q = foldDiacritics($.trim(query || "")); resultsList.empty(); activeIndex = -1; var matched = []; if (q) { $.each(allOptions, function (i, o) { if (o.disabled) return; var rank = rankOption(o, q); if (rank !== RANK_NONE) matched.push({ opt: o, rank: rank, i: i }); }); if (!matched.length && q.indexOf(" ") !== -1) { var tokens = q.split(/\s+/); $.each(allOptions, function (i, o) { if (o.disabled) return; var all = true; $.each(tokens, function (_, t) { if (o.foldText.indexOf(t) === -1) { all = false; return false; } }); if (all) matched.push({ opt: o, rank: 8, i: i }); }); } matched.sort(function (a, b) { if (a.rank !== b.rank) return a.rank - b.rank; // Inside the code tiers the shorter code is the better hit: // "an" -> "an" before "ang" before "ang-x-...". if (a.rank <= 1 && a.opt.foldCode.length !== b.opt.foldCode.length) { return a.opt.foldCode.length - b.opt.foldCode.length; } // Otherwise keep the menu's own order (pinned languages first). return a.i - b.i; }); } else { $.each(allOptions, function (i, o) { if (!o.disabled) matched.push({ opt: o, rank: 0, i: i }); }); } shown = $.map(matched.slice(0, 50), function (m) { return m.opt; }); if (!shown.length) { closeList(); return; } $.each(shown, function (idx, opt) { var li = $("<li role='option'></li>") .text(opt.text) .attr("data-value", opt.value) .attr("aria-selected", "false"); // touchend (not touchstart) so a scroll doesn't trigger a select. 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); }); // mousedown (not click) so it beats the input's blur handler. li.on("mousedown", function (e) { e.preventDefault(); selectOption(opt.value, opt.text); }); li.on("mouseenter", function () { // Hovered items are already in view -- don't scroll the list // under the mouse, or the shift can trigger the next item's // mouseenter and cascade into a runaway scroll. setActive(idx, /* scrollIntoView */ false); }); resultsList.append(li); }); positionList(); resultsList.show(); resultsList[0].scrollTop = 0; textInput.attr("aria-expanded", "true"); } function setActive(idx, scrollIntoView) { var items = resultsList.children("li"); if (!items.length) return; if (idx < 0) idx = items.length - 1; if (idx >= items.length) idx = 0; activeIndex = idx; items.removeClass("wiktku-ac-active").attr("aria-selected", "false"); var li = items.eq(idx).addClass("wiktku-ac-active").attr("aria-selected", "true"); if (scrollIntoView === false) return; // Keep the cursor visible inside the scrollable list -- only for // keyboard navigation. A mouse-hovered item is already visible, so // scrolling here would shift the list under a stationary pointer // and cascade into further mouseenter events. var ul = resultsList[0], el = li[0]; if (el.offsetTop < ul.scrollTop) { ul.scrollTop = el.offsetTop; } else if (el.offsetTop + el.offsetHeight > ul.scrollTop + ul.clientHeight) { ul.scrollTop = el.offsetTop + el.offsetHeight - ul.clientHeight; } } /** Puts the currently selected option's label back in the text box. */ function syncInputToSelect() { var cur = select.val(); var match = null; if (cur) { $.each(allOptions, function (_, o) { if (o.value === cur) { match = o; return false; } }); } textInput.val(match ? match.text : ""); } function selectOption(value, text) { textInput.val(text); select.val(value); closeList(); select.trigger("change"); } textInput.on("input", function () { showResults($(this).val()); }); textInput.on("focus", function () { // Select the current label so typing replaces it, and open the full list this.select(); showResults(""); }); textInput.on("click", function () { if (!resultsList.is(":visible")) showResults($(this).val()); }); textInput.on("keydown", function (e) { var open = resultsList.is(":visible"); switch (e.which) { case 40: // Down e.preventDefault(); if (!open) { showResults($(this).val()); setActive(0); } else setActive(activeIndex + 1); break; case 38: // Up e.preventDefault(); if (!open) { showResults($(this).val()); setActive(-1); } else setActive(activeIndex - 1); break; case 13: // Enter -- must never submit the form while the list is open if (open) { e.preventDefault(); if (activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } else if (shown.length === 1) { selectOption(shown[0].value, shown[0].text); } } break; case 27: // Esc -- abandon the search, restore the real value if (open) { e.preventDefault(); closeList(); syncInputToSelect(); } break; case 9: // Tab -- commit the highlighted row on the way out if (open && activeIndex >= 0 && shown[activeIndex]) { selectOption(shown[activeIndex].value, shown[activeIndex].text); } closeList(); break; } }); textInput.on("blur", function () { // Short delay so a touchstart/mousedown on a result fires first. setTimeout(function () { closeList(); // Half-typed text that never became a selection would otherwise sit // in the box looking like a choice -- put the real value back. syncInputToSelect(); }, 200); }); // Re-caches the option list. Fired after ziman.json loads, after // options are enabled/disabled, and after programmatic .val() changes. select.on("wiktku:refresh", function () { cacheOptions(); syncInputToSelect(); if (resultsList.is(":visible")) showResults(textInput.val()); }); wrapper.append(textInput).append(resultsList).append(select); return wrapper; } /** * Gives every plain <select> under `root` the searchable picker. Selects * marked .wiktku-plain-select opt out, and the call is idempotent, so it is * safe to re-run after new rows or sense blocks are inserted. */ function initSelects(root) { $(root).find("select").addBack("select").not(".wiktku-plain-select").each(function () { var sel = $(this); if (sel.prop("multiple")) return; if (sel.closest(".wiktku-native-select-wrap").length) return; // already wrapped var marker = $("<span></span>").insertBefore(sel); marker.replaceWith(wrapNativeSelect(sel)); }); } var langsByCode = {}; // Populated from [[MediaWiki:Gadget-start.js/data.json]] at runtime. var metadata = {}; var ZARAVA_LANG_CODES = ["ckb", "sdh", "lki", "hac", "zza"]; // Converts a {code: label} object (langChoices/posChoices in data.json) // into the {code, label[, sortKey]} array the rest of the script uses. // isLang: true adds a sortKey and shows "(code)" after the label — // language choices only. function choicesFromObject(obj, isLang) { var result = []; $.each(obj || {}, function (code, label) { var choice = { code: code, label: label }; if (isLang) choice.sortKey = label; result.push(choice); }); return result; } function getZaravaKeys(choices) { var byCode = {}; $.each(choices || [], function (_, c) { byCode[c.code] = c; }); var result = []; $.each(ZARAVA_LANG_CODES, function (_, code) { if (byCode[code]) result.push(byCode[code]); }); return result; } 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 — ji data.json tê dagirtin var GENDER_BASE_LABELS = {}; // Sub-lists that only make sense for a plain (non-şablon) sense — hidden // when a şablon (e.g. {{guharto|…}}) is chosen for that sense var HIDDEN_ON_TPL_GROUPS = [ "wiktku-dfn-alternativ", "wiktku-dfn-hevmane", "wiktku-dfn-dijmane", "wiktku-dfn-koordine", "wiktku-dfn-jornav", "wiktku-dfn-jernav" ]; 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; } // True if a sense has content beyond mane worth keeping (etîket, word // lists, nimûne, jêder) — so it's still emitted with {{mane?}} if empty. function senseHasExtraContent(s) { if (s.etiket && $.grep(s.etiket, function (e) { return $.trim(e) !== ""; }).length) return true; if (s.kategori && $.grep(s.kategori, function (k) { return $.trim(k) !== ""; }).length) return true; if (s.alternativ.length || s.hevmane.length || s.dijmane.length || s.koordine.length || s.jornav.length || s.jernav.length) return true; if (s.nimune && $.grep(s.nimune, function (n) { return (typeof n === "object" ? n.text : n) !== ""; }).length > 0) return true; if (senseHasJeder(s)) return true; return false; } // Each nimûne item can be { text, tr, t }: text, transliteration, translation. 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 jêder (citation) entries into "#* {{jêder…|…}}" lines; skips // entries with no quote text. Falls back to the generic {{jêder}} // template when no specific template was chosen. 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; // A şablon picked from Kategorî:Çavkanî is transcluded as the // source param (e.g. |{{Kovara X}}); manual text is used as-is. var srcParam = jeder.jederCatTpl ? ("{{" + jeder.jederCatTpl + "}}") : (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(""); } // True if a sense has at least one jêder entry with quote text. function senseHasJeder(sense) { return !!(sense.jeder && $.grep(sense.jeder, function (j) { return j && j.quote; }).length > 0); } // Builds "{{tplName|lang|part1|part2|…}}" from a sense field (kategori, // etiket), wrapped inline (" {{…}} ") or on its own line ("\n#: {{…}}"). function buildSenseTpl(sense, field, lang, tplName) { if (!sense[field] || !sense[field].length) return ""; var parts = sense[field].map(function (p) { return $.trim(p); }) .filter(function (p) { return p !== ""; }); if (!parts.length) return ""; var call = "{{" + tplName + "|" + lang + "|" + parts.join("|") + "}}"; return call } /** * Assembles the nimûne + jêder wikitext block for a sense. Shared by * both the template-sense and normal-mane-sense branches below. */ function buildCite(sense, lang) { return formatNimune(sense.nimune, lang, senseHasJeder(sense)) + formatJeder(sense.jeder, lang); } function makeWordListStep(id, name, question_fmt, header, templateName) { return { id: id, name: name, question_fmt: question_fmt, multiple: true, narrow: true, placeholder: "Kelîme…", 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 = "\n==== " + header + " ====\n"; if (words.length === 1) { // Single word — keep the simple inline template. return section + "* {{g|" + lang + "|" + words[0] + "}}\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 + "|" + 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) { if (addLangMode){ return "\n== {{ziman|" + values.lang + "}} ==\n"; }else { return "== {{ziman|" + values.lang + "}} ==\n"; } } }, pron: { id: "pron", name: "bilêvkirin", question_fmt: '"' + pageName + '" çawa tê telafûzkirin?', // pronTpls populated from data.json pronTpls: {}, visible: function (values) { if (!values.lang) return false; // addLangMode: skip pron only if this lang already has a section. if (addLangMode) { // Clearing the page makes existing content irrelevant. var clearPageCheck = $("#wiktku-clear-page-check"); if (clearPageCheck.length && clearPageCheck.prop("checked")) { return true; } var existing = $("#wpTextbox1").val() || ""; return !findLangHeader(existing, values.lang); } return true; }, // Fills the insert-dropdown from pronTpls, filtered 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 (name, 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(name + " — " + tpl.desc) .attr("data-nolang", tpl.noLang ? "1" : "")); } }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike "); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var lang = getValues().lang || ""; $.each(steps.pron.pronTpls, function (name, 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(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(""); // Clear the picker's search box too, so it goes back to its // placeholder instead of keeping the inserted template name. sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel).append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function () { 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 "\n=== Bilêvkirin ===\n" + out + "\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 = "\n=== " + 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 (gender) — shown for navdêr/serenav only, with choices built // from metadata[lang].g since not every language has grammatical gender. 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 wiktku-plain-select", 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: code, label: genderLabel(code) }]; }); populateMenus(select, choices, null, "Cinsiyetê hilbijêre"); if ($.grep(choices, function (c) { return c.code === prevVal; }).length) { select.val(prevVal); } return select; }, output: function () { return ""; } // consumed by pos.output }, // Lêker transitivity 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. // NOTE: populateMenus() expects {code, label} objects (like every // other step's choices) — plain [code, label] pairs would leave // choice.code/choice.label undefined. choices: [ { code: "gh", label: "gerguhêz" }, { code: "x-gh", label: "xwerû-gerguhêz" }, { code: "p-gh", label: "pêkhatî-gerguhêz" }, { code: "h-gh", label: "hevedudanî-gerguhêz" }, { code: "b-gh", label: "biwêjî-gerguhêz" }, { code: "ngh", label: "negerguhêz" }, { code: "x-ngh", label: "xwerû-negerguhêz" }, { code: "p-ngh", label: "pêkhatî-negerguhêz" }, { code: "h-ngh", label: "hevedudanî-negerguhêz" }, { code: "b-ngh", label: "biwêjî-negerguhêz" } ], output: function () { return ""; } // consumed by pos.output }, tr: { id: "tr", name: "translîterasyon", question_fmt: "Translîterasyona vê kelîmeyê", multiple: false, narrow: true, visible: function (values) { return values.lang && values.pos && needsTransliteration(values.lang); } }, dfn: { id: "dfn", name: "Mane", // Werger-section reminder only makes sense for ku entries — for // any other language the mane box turns into tercime+îzah instead // (see buildSenseBlock's updateManeMode) question_fmt: function (values) { var lang = (values && values.lang) || ""; var base = "Maneya kelîmeyê binivîse. Mane otomatîk tê lînkkirin!"; if (lang === "ku") { return base + " Ji bo tercimeyan beşa 'Werger' bi kar bîne!"; } return base; }, 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>): mane textarea, nimûne list, and // sub-lists for alternatîv/hevmane/dijmane/etc. 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); }); // — Tercime + Îzah boxes (non-ku alternative to the plain mane box) — // Non-ku entries get a direct translation plus a {{îzah|…}}-wrapped // gloss instead of a Kurdish-style gloss. Rather than teach every // consumer (getSenses/getOutput/linkify) a second data shape, these // boxes just write their combined text into dfnArea and re-fire its // "input" event, so dfnArea stays the single source of truth. var wergerArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-werger-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-werger") .attr("rows", 2) .attr("placeholder", "Tercimeyên rasterast ên kurmancî…"); var izahArea = $("<textarea></textarea>") .attr("name", "wiktku-dfn-izah-" + $.now() + "-" + Math.random().toString(36).substr(2, 9)) .attr("class", "wiktku-dfn-subfield wiktku-dfn-izah") .attr("rows", 3) .attr("placeholder", "Îzaha kurmancî binivîse…"); var nonKuWrap = $("<div class='wiktku-dfn-nonku-wrap'></div>") .append(wergerArea).append(izahArea) .hide(); function syncNonKuToMane() { var w = $.trim(wergerArea.val()); var iz = $.trim(izahArea.val()); // {{îzah|…}} only makes sense as an addendum to an actual // translation — if werger is left blank, there's nothing for // it to clarify, so just use the îzah text as the definition // itself instead of wrapping it in a now-pointless template. var combined = w ? (iz ? w + " {{îzah|" + iz + "}}" : w) : iz; dfnArea.val(combined); // Re-fires onDfnInput so the sense list still grows and // refresh() still runs, exactly as if this were typed // directly into the mane textarea. dfnArea.trigger("input"); } wergerArea.on("input", syncNonKuToMane); izahArea.on("input", syncNonKuToMane); // Switches between the plain mane box and the werger+îzah pair — // the latter only for non-ku entries with no şablon selected. function updateManeMode() { var lang = getValues().lang || ""; var isTpl = !!tplSelect.val(); if (lang && lang !== "ku" && !isTpl) { dfnArea.hide(); nonKuWrap.show(); } else { nonKuWrap.hide(); if (!isTpl) dfnArea.show(); } } // Store on the block so refresh() can re-sync every block when // lang changes, and restoreDfn() can re-sync after restoring. block.data("updateManeMode", updateManeMode); // — 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, so updateTplOptions // can detach/re-attach them without losing the full list. var _allTplOptions = []; var tplSelect = $(mw.html.element("select", { "class": "wiktku-dfn-tpl-select" })); tplSelect.attr("data-placeholder", "Şablonê lê bigere"); tplSelect.append($("<option value=''>— yan jî şablonek hilbijêre —</option>")); $.each(tplDefs, function (name, tpl) { var opt = $("<option></option>") .val(name) .text(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 — native <select> won't reliably hide options any other way. 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; } }); tplSelect.trigger("wiktku:refresh"); if (currentVal && !currentStillValid) { tplSelect.val(""); tplTitleInput.hide().val(""); updateManeMode(); } } // 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); }); // Şablon senses have no plain gloss, so hide alternatîv/hevmane/ // dijmane/etc. Etîket, Nimûne and Jêgirtin stay visible either way. function updateFieldVisibility() { var isTpl = !!tplSelect.val(); $.each(HIDDEN_ON_TPL_GROUPS, function (_, cls) { block.find("." + cls + "-group").toggle(!isTpl); }); } // Store on the block so restoreDfn() can re-sync visibility // after programmatically setting tplSelect's value. block.data("updateFieldVisibility", updateFieldVisibility); tplSelect.on("change", function () { var chosen = $(this).val(); if (chosen) { dfnArea.hide(); nonKuWrap.hide(); tplTitleInput.show().focus(); } else { tplTitleInput.hide().val(""); updateManeMode(); } updateFieldVisibility(); // 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); block.append(nonKuWrap); // Apply lang filter on initial build. updateTplOptions(); updateManeMode(); // — 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, Mêrdîn, anatomî, Badînî" }, { cls: "wiktku-dfn-kategori", label: "Kategorî", rows: 1, narrow: true, izah: "wekî etîket lê xuya nabe tenê kategorîze dike" }, { cls: "wiktku-dfn-alternativ", label: "Formên alternatîv", 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": "); 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") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text(g.label)) .append(": ") .append($("<span></span>").addClass("wiktku-dfn-sublabel-hint").text(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 (citation) group — growing list, same structure as Nimûne. — (function () { var jederGroupDiv = $("<div></div>").addClass("wiktku-dfn-subgroup wiktku-dfn-jeder-group"); var jederLbl = $("<span></span>").addClass("wiktku-dfn-sublabel") .append($("<span></span>").addClass("wiktku-dfn-sublabel-term").text("Jêgirtin")) .append(": "); 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"); var dragHandle = $("<span></span>") .addClass("wiktku-jeder-drag-handle") .attr("title", "Bişkûne û bikişîne da ku rêzê biguhezîne"); // 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(dragHandle).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); // Citoid auto-fill: fetch citation data from a URL, DOI or ISBN and // prefill the source şablon + fields below (see Gadget-citoid-helper.js). var citoidWrap = $("<div></div>").addClass("wiktku-dfn-quote-citoid"); var citoidInput = $("<input type='text'>") .addClass("wiktku-dfn-quote-citoid-input wiktku-start-narrow") .attr("placeholder", "URL, DOI an ISBN binivîse ku otomatîk were tijekirin…"); var citoidBtn = new OO.ui.ButtonWidget({ label: "Bi Citoid bîne", classes: [ "wiktku-dfn-quote-citoid-btn" ] }); var citoidStatus = $("<span></span>").addClass("wiktku-dfn-quote-citoid-status"); // Fetches citation data from Citoid and fills this citation's // şablon + fields — only rebuilds fields on template change, // and never overwrites values the user already typed. function runCitoidFetch() { var query = $.trim(citoidInput.val()); if (!query) { mw.notify("Ji kerema xwe re pêşî URL, DOI an ISBNyekê binivîse."); return; } citoidBtn.setDisabled(true); citoidStatus.text("Tê anîn…"); wikt.citoidHelper.ensure().then(function () { return wikt.citoid.fetchJederFields(query); }).then(function (result) { var jederKey = result.jederKey; var hasTpl = !!jederKey && srcSel.find("option[value='" + jederKey + "']").length > 0; var targetVal = hasTpl ? jederKey : "__manual__"; // Only rebuild if switching şablon, so a repeat fetch // doesn't clear fields already filled in by hand. if (srcSel.val() !== targetVal) { srcSel.val(targetVal).trigger("change"); } if (hasTpl) { // Tenê qadên vala tijî bike. $.each(result.fields, function (key, val) { var input = srcFields.find("[data-field-key='" + key + "']"); if (input.length && !$.trim(input.val())) { input.val(val); } }); } else { // Şablonek nehat naskirin ji bo vê itemType — rêzikeke // çavkaniyê ya bi destan a ji qadên Citoid tê çêkirin, // lê tenê ger qada destan vala be. var manualField = srcFields.find(".wiktku-dfn-quote-src-manual"); if (!$.trim(manualField.val())) { var parts = []; $.each(["nivîskar", "sernav", "websîte", "kovar", "weşanxane", "sal", "url"], function (_, k) { if (result.fields[k]) parts.push(result.fields[k]); }); manualField.val(parts.join(", ")); } } citoidStatus.text(""); }, function (errorMsg) { citoidStatus.text(typeof errorMsg === "string" ? errorMsg : "Nehat dîtin. Kontrol bike ka URL/DOI/ISBN rast e."); }).always(function () { citoidBtn.setDisabled(false); }); } citoidBtn.on("click", runCitoidFetch); citoidInput.on("keydown", function (e) { if (e.which === 13) { // Enter e.preventDefault(); runCitoidFetch(); } }); citoidWrap.append(citoidInput).append(citoidBtn.$element).append(citoidStatus); // Source template selector, specific to this citation. var srcSel = $("<select></select>").addClass("wiktku-dfn-quote-src-sel wiktku-plain-select"); srcSel.append($("<option value=''>— Çavkaniyê hilbijêre —</option>")); srcSel.append($("<option></option>").val("__manual__").text("Bi destê xwe binivîsim")); srcSel.append($("<option></option>").val("__category__").text("Ji Kategorî:Çavkanî şablonekê hilbijêre")); 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; } if (chosen === "__category__") { // Search widget over the members of [[Kategorî:Çavkanî]]. // Picking a şablon here immediately switches the row to // "Bi destê xwe binivîsim" mode with {{Şablon}} pre-filled, // so the saved value is always exactly what's in that // (editable) textarea — no separate hidden field that can // end up empty and silently fall back to "çavkanî?". var catWrap = $("<span></span>").addClass("wiktku-native-select-wrap wiktku-dfn-quote-src-cat"); var catInput = $("<input type='search' autocomplete='off'>") .addClass("wiktku-start-narrow wiktku-dfn-quote-src-cat-input") .attr("placeholder", "Navê şablonê lê bigere…"); var catResults = $("<ul></ul>").addClass("wiktku-ac-results wiktku-dfn-quote-src-cat-results").hide(); var catStatus = $("<span></span>").addClass("wiktku-dfn-quote-src-cat-status").text("Şablon tên barkirin…"); function showCatResults(query) { var q = $.trim(query).toLowerCase(); catResults.empty(); var list = catSrcTemplates || []; var matched = q ? $.grep(list, function (name) { return name.toLowerCase().indexOf(q) !== -1; }) : list; if (!matched.length) { catResults.hide(); return; } $.each(matched.slice(0, 50), function (_, name) { var li = $("<li></li>").text(name).attr("data-value", name); var touchMoved = false; li.on("touchstart", function () { touchMoved = false; }); li.on("touchmove", function () { touchMoved = true; }); li.on("touchend", function (e) { if (touchMoved) return; e.preventDefault(); selectCatTpl(name); }); li.on("mousedown", function (e) { e.preventDefault(); selectCatTpl(name); }); catResults.append(li); }); catResults.show(); } // Wraps the chosen şablon as {{Name}}, drops it into the // manual textarea, and switches the row into manual mode // so the user can keep editing it (add params, etc.). function selectCatTpl(name) { catResults.hide(); srcSel.val("__manual__"); srcSel.trigger("change"); srcFields.find(".wiktku-dfn-quote-src-manual") .val("{{" + name + "}}") .trigger("focus"); } catInput.on("input", function () { showCatResults($(this).val()); }); catInput.on("focus", function () { showCatResults($(this).val()); }); catInput.on("blur", function () { setTimeout(function () { catResults.hide(); }, 200); }); catWrap.append(catInput).append(catResults).append(catStatus); srcFields.append(catWrap); fetchCatSrcTemplates().then(function () { catStatus.text(""); }, function () { catStatus.text("Şablon nehatin barkirin."); }); return; } var def = (steps.dfn.jederDefs || {})[chosen]; if (!def) return; $.each(def.fields, function (key, label) { var row = $("<div></div>").addClass("wiktku-dfn-quote-src-row"); var fieldLbl = $("<label></label>").text(label + ": "); var inp = $("<textarea></textarea>") .attr("rows", 2) .addClass("wiktku-dfn-quote-src-input wiktku-start-narrow") .attr("data-field-key", key) .attr("placeholder", label + "…"); // "Sernav" / "Sernavê orjînal" (title fields, e.g. for // kitêb/kovar/malper) get a taller, draggable box; every // other field in the template stays as-is. Field labels // come from the on-wiki jederDefs data, so match on the // (diacritic-folded) label text rather than a fixed key. var foldedLabel = foldDiacritics(label); if (/^sernav$/.test(foldedLabel) || /orjin/.test(foldedLabel)) { inp.addClass("wiktku-dfn-quote-src-input--title"); } row.append(fieldLbl).append(inp); srcFields.append(row); }); }); li.append(citoidWrap).append(srcSel).append(srcFields); return li; } jederGroupDiv.data("buildJederLi", buildJederLi); jederList.append(buildJederLi()); // Make citation rows sortable (drag to reorder). // The last row is always the empty trailing row — cancel its drag. mw.loader.using("jquery.ui.sortable", function () { jederList.sortable({ handle: ".wiktku-jeder-drag-handle", axis: "y", items: "li:not(:last-child)", tolerance: "pointer" }); }); jederGroupDiv.append(jederLbl).append(jederList); block.append(jederGroupDiv); }()); // Apply the initial hide/show state for the sub-groups (matches // tplSelect's starting value, which is normally empty). updateFieldVisibility(); 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); // Give the new block's template selector the searchable picker. initSelects(newBlock); } refresh(); }, /** Grows a sub-list (nimûne/formên alternatîv/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, posExamples, jederDefs). tplDefs: {}, posExamples: {}, jederDefs: {}, build: function (stepDiv) { 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()); 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 === "__category__") { // Reachable only if the user opened the category search but // never picked a şablon — picking one switches the row to // __manual__ (see selectCatTpl above), so there's nothing // meaningful to save here. } 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: readList("wiktku-dfn-etiket"), kategori: readList("wiktku-dfn-kategori"), nimune: readNimuneList(), jeder: readJederList(), alternativ: readList("wiktku-dfn-alternativ"), 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 a mane, a chosen template + title, // or any other content (etîket/hevmane/nimûne/jêder…) worth keeping. var hasMane = senses.some(function (s) { return s.mane !== "" || (s.tpl && s.tplTitle) || senseHasExtraContent(s); }); // nimûne/jêder must never pass through linkify, only the mane text. // defLines (linkified) and citeLines (kept aside) stay parallel; // a {{wiktku-cite-N}} token in defLines marks where to splice back. // izahLines is a third parallel array — unlike nimûne/jêder we DO // want îzah glosses linkified, just via their own separate pass // (see the two linkifyText() calls below), so a {{wiktku-izah-N}} // token marks where to splice that in too. var defLines = []; // one entry per kept sense (goes to linkify) var citeLines = []; // parallel — nimûne+jêder for that same sense var izahLines = []; // parallel — raw îzah gloss for that same sense // True only once some sense's *actual* dfn text (post werger/îzah // split) is non-empty. A non-ku sense with werger left blank and // only îzah filled in has sense.mane === "{{îzah|…}}", which is // truthy, but splits down to an empty dfn — so it must NOT count // here. Sending a "# {{wiktku-izah-N}}" line (a bare template // call with no plain words at all) through the main linkify pass // is what makes the linkify gadget hang, since it has nothing to // word-link on that line. Skipping the main pass in that case is // what fixes the freeze. var hasLinkableMane = false; $.each(senses, function (_, sense) { // — Template sense (e.g. {{guharto|ku|somepage}}) — if (sense.tpl) { if (!sense.tplTitle) return; // skip empty template senses var tplKatTpl = buildSenseTpl(sense, "kategori", lang, "K"); var tplLabelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var tplCall = sense.tplNoLang ? "{{" + sense.tpl + "|" + sense.tplTitle + "}}" : "{{" + sense.tpl + "|" + lang + "|" + sense.tplTitle + "}}"; var idx = defLines.length; var cite = buildCite(sense, lang); defLines.push("# " + (tplKatTpl ? tplKatTpl + " " : "") + (tplLabelTpl ? tplLabelTpl + " " : "") + tplCall + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(""); // template senses have no îzah return; } // — Normal mane sense — var dfn = sense.mane; if (!dfn && !senseHasExtraContent(sense)) return; // truly empty // Pull the îzah gloss (if any) out of the combined werger+îzah // string — it's spliced back in separately below, after its // own linkify pass (see izahLines / the second linkifyText call). var izahRaw = null; var wergerIzah = splitWergerIzah(dfn); if (wergerIzah) { dfn = wergerIzah.werger; izahRaw = stripWikilinks(wergerIzah.izah); } if (dfn) { dfn = stripWikilinks(dfn); // Sentence-case + trailing period are for ku definitions, // which are written as full glosses. A non-ku werger is // just the translation term itself, so its case and // punctuation are left exactly as the editor typed them. if (lang === "ku") { if (dfn[0] !== dfn[0].toUpperCase()) dfn = capitalize(dfn); if (!dfn.match(/[.…?!)\]]$/)) dfn += "."; } } else if (izahRaw === null) { // {{mane?}} is a ku-specific "no definition yet" nudge — // don't stamp it on a non-ku sense that's only missing // its werger (e.g. îzah alone, or other fields only). dfn = lang === "ku" ? "{{mane?|" + lang + "}}" : ""; } if (dfn) hasLinkableMane = true; var katTpl = buildSenseTpl(sense, "kategori", lang, "K"); var labelTpl = buildSenseTpl(sense, "etiket", lang, "e"); var out = "# " + (katTpl ? katTpl + " " : "") + (labelTpl ? labelTpl + " " : "") + dfn; var idx = defLines.length; var hasThisIzah = izahRaw !== null && $.trim(izahRaw) !== ""; // Bare {{...}} token — like {{wiktku-cite-N}}, this survives // linkify's first pass untouched (it treats template calls as // opaque), then gets swapped for {{îzah|…}} once the actual // gloss text has been linkified in its own separate pass. if (hasThisIzah) { out += (dfn ? " " : "") + "{{wiktku-izah-" + idx + "}}"; } function wordLine(tpl, words) { if (!words.length) return ""; return "\n#: {{" + tpl + "|" + lang + "|" + words.join("|") + "}}"; } out += wordLine("alt-r", sense.alternativ); 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); var cite = buildCite(sense, lang); defLines.push(out + (cite ? "{{wiktku-cite-" + idx + "}}" : "")); citeLines.push(cite); izahLines.push(hasThisIzah ? izahRaw : ""); }); // Splice citeLines back into a linkified string, replacing each // {{wiktku-cite-N}} token with its stored nimûne/jêder block. function restoreCites(t) { return t.replace(/\{\{wiktku-cite-(\d+)\}\}/g, function (_, n) { return citeLines[parseInt(n, 10)] || ""; }); } // Runs text through the linkify gadget if it's loaded, otherwise // just passes it through unchanged. Shared by both linkify passes // below (main mane text, and — separately — îzah glosses). function linkifyText(t, cb) { if (typeof $.wiktviLinkify === "function") { $.wiktviLinkify(t, cb); } else { cb(t); } } var hasIzah = izahLines.some(function (t) { return t && $.trim(t) !== ""; }); var text = defLines.join("\n") + "\n"; if (!hasMane) { // No definitions entered — emit {{mane?}} with bênimûne. text = "# {{mane?|" + lang + "}}\n#* {{bênimûne|" + lang + "}}\n"; callback(text); return; } // Runs the îzah-only linkify pass against `base` (either the raw // text, when there's no linkable mane to run the main pass on // first, or the already-linkified main text). Shared by both // branches below so the token-splice logic only lives once. function runIzahPass(base) { var izahJoined = $.map(izahLines, function (raw, idx) { if (!raw) return undefined; return "{{wiktku-izah-open-" + idx + "}}" + raw + "{{wiktku-izah-close-" + idx + "}}"; }).join("\n"); linkifyText(izahJoined, function (izahLinked) { var izahByIdx = {}; var re = /\{\{wiktku-izah-open-(\d+)\}\}([\s\S]*?)\{\{wiktku-izah-close-\1\}\}/g; var m; while ((m = re.exec(izahLinked)) !== null) { izahByIdx[parseInt(m[1], 10)] = m[2]; } var withIzah = base.replace(/\{\{wiktku-izah-(\d+)\}\}/g, function (_, n) { var linked = izahByIdx[parseInt(n, 10)]; return linked !== undefined ? "{{îzah|" + linked + "}}" : ""; }); callback(restoreCites(withIzah)); }); } if (!hasLinkableMane) { if (!hasIzah) { // All filled senses are template senses (or otherwise have // no plain text at all) — nothing here needs linkify. callback(restoreCites(text)); return; } // There's no plain mane text anywhere (e.g. werger left blank // with only îzah filled in), so every defLine is just a bare // template call with nothing to word-link. Sending a line // like "# {{wiktku-izah-0}}" through the main linkify pass // gives it no plain words to work with, which is what made // the gadget hang — so skip that pass entirely and run only // the îzah pass, splicing straight into the unlinkified text. var loadIzahOnly = function () { runIzahPass(text); }; mw.loader.using("ext.gadget.linkify", loadIzahOnly, loadIzahOnly); return; } var didTryToLoad = function () { // First pass: the main definition text (mane), same as before. linkifyText(text, function (mainLinked) { if (!hasIzah) { callback(restoreCites(mainLinked)); return; } // Second pass: îzah glosses, linkified via their own // separate call — simpler and more robust than trying to // smuggle them through the first pass behind sentinel // characters. Each gloss is wrapped in its own // {{wiktku-izah-open/close-N}} pair; like the existing // {{wiktku-cite-N}} tokens, these sit inside double // braces so linkify leaves the tokens themselves alone — // only the raw gloss text between each pair gets linked. runIzahPass(mainLinked); }); }; mw.loader.using("ext.gadget.linkify", didTryToLoad, didTryToLoad); } }, je: makeWordListStep("je", "jê", "Kelîmeyên jê çêbûyî binivîse", "Jê"), tekildar: makeWordListStep("tekildar", "têkildar", "Kelîmeyên ji aliyê etîmolojiyê ve têkildarî vê kelîmeyê binivîse", "Têkildar"), binereherwiha: makeWordListStep("binereherwiha", "binêre herwiha", "Kelîmeyên din ên eleqedar binivîse", "Binêre herwiha"), 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 the insert-dropdown from the current etymTpls object. 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 (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(name + " — " + tpl.desc)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, 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.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); $.each(steps.etym.etymTpls, function (name, tpl) { sel.append($("<option></option>").val(tpl.snippet).text(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(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(ta); stepDiv.append(wrap); initSelects(wrap); return ta; }, output: function (values) { var text = $.trim($("#wiktku-start-etym .wiktku-etym-text").val()); if (text) { return "\n==== Etîmolojî ====\n" + text + "\n"; } // No etymology entered — emit {{ji?|lang}} as a placeholder. // Skip it only when every filled sense is a şablon sense (the // template covers this already); a completely empty entry with // no şablon chosen still gets the placeholder, same as before // dfn had any content at all. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasFilledTplSense = dfnSenses.some(function (s) { return !!s.tpl && !!s.tplTitle; }); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); if (hasFilledTplSense && !hasRegularMane) return ""; return "\n==== Etîmolojî ====\n{{ji?|" + values.lang + "}}\n"; } }, dunde: { id: "dunde", name: "dûnde", question_fmt: "Eger ev kelîme ji vî zimanî ketibe zimanekî din, vî zimanî û kelîmeya wî binivîse", visible: function (values) { return !!values.pos; }, disabledKeys: { "navz": true}, // Language dropdown + growing word-input list; a new row appends // when the dropdown gets a value. Mirrors steps.trans, but flat. buildRow: function (stepDiv) { var row = $("<li class='wiktku-dunde-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/build below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); 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 () { var stepDiv = $("#wiktku-start-dunde"); var rows = steps.dunde.getRows(stepDiv); if (!rows.length) return ""; var lines = $.map(rows, function (row) { var lang = row[0], words = row[1]; return "* {{dû|" + lang + "|" + words.join("|") + "}}"; }); return "\n==== Dûnde ====\n" + lines.join("\n") + "\n"; } }, zarava: { id: "zarava", name: "bi zaravayên din", question_fmt: "Eger ev kelîme di zaravayên din de bi awayekî cuda tê gotin an nivîsandin, wan lê zêde bike", visible: function (values) { return steps.trans.visible(values); }, disabledKeys: { "navz": true }, buildRow: function (group) { var row = $("<li class='wiktku-zarava-row wiktku-lang-row'></li>"); var langSel = $(mw.html.element("select", { "class": "wiktku-start-step-keyfield wiktku-start-narrow" })); langSel.attr("data-placeholder", "Zaravayekî lê bigere"); populateMenus(langSel, steps.zarava.keys || [], steps.zarava.disabledKeys); langSel.on("change", function () { steps.zarava.onLangChange(group, row); }); var wordList = $("<ul class='wiktku-zarava-words wiktku-lang-row-words'></ul>"); var firstWord = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(firstWord)); row.append(langSel).append(wordList); return row; }, makeWordInput: function () { var input = $("<textarea></textarea>") .attr("name", "wiktku-zarava-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-zarava-words"); var item = $(this).parent(); var val = $.trim($(this).val()); if (val && item.is(list.children("li:last-child"))) { var next = steps.zarava.makeWordInput(); list.append($("<li></li>").append(next)); } }); return input; }, onLangChange: function (group, row) { var list = group.find("ul.wiktku-zarava-list"); var isLast = row.is(list.children("li.wiktku-zarava-row:last-child")); if (isLast) { var newRow = steps.zarava.buildRow(group); list.append(newRow); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } steps.zarava.syncDisabledKeys(group); }, /** Disables already-selected dialects in all other dropdowns within one group. */ syncDisabledKeys: function (group) { var taken = $.extend({}, steps.zarava.disabledKeys); group.find("li.wiktku-zarava-row select").each(function () { var v = $(this).val(); if (v) taken[v] = true; }); group.find("li.wiktku-zarava-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("wiktku:refresh"); }); }, /** Builds (or fetches) the .wiktku-zarava-group for one gloss. */ buildGroup: function (stepDiv, gi) { var group = $("<div class='wiktku-zarava-group'></div>").attr("data-gloss-pos", gi); var list = $("<ul class='wiktku-zarava-list wiktku-lang-row-list'></ul>"); list.append(steps.zarava.buildRow(group)); group.append(list); stepDiv.append(group); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, /** Syncs one .wiktku-zarava-group per current gloss (same logic as steps.trans.build). */ build: function (stepDiv) { var glosses = steps.trans.glossList(); if (!glosses.length) { stepDiv.find(".wiktku-zarava-group").remove(); return null; } var existingGroups = stepDiv.find(".wiktku-zarava-group"); if (existingGroups.length > glosses.length) { existingGroups.slice(glosses.length).remove(); } $.each(glosses, function (gi, gloss) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) group = steps.zarava.buildGroup(stepDiv, gi); var label = group.find(".wiktku-zarava-group-label"); if (glosses.length > 1) { if (!label.length) { label = $("<div class='wiktku-zarava-group-label'></div>"); group.prepend(label); } label.text(gloss.index + " " + gloss.text); } else if (label.length) { label.remove(); } }); return null; }, /** Reads the dialect rows for a single gloss group. */ getGroupTranslations: function (group) { var result = []; group.find("li.wiktku-zarava-row").each(function () { var lang = $(this).find("select").val(); if (!lang) return; var words = []; $(this).find("ul.wiktku-zarava-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 rows from the DOM, grouped by gloss position. */ getTranslations: function (stepDiv) { var result = []; stepDiv.find(".wiktku-zarava-group").each(function () { result.push(steps.zarava.getGroupTranslations($(this))); }); return result; }, output: function (values) { if (values.lang !== "ku") return ""; var stepDiv = $("#wiktku-start-zarava"); var glosses = steps.trans.glossList(); if (!glosses.length) return ""; var blocks = $.map(glosses, function (gloss, gi) { var group = stepDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); var rows = group.length ? steps.zarava.getGroupTranslations(group) : []; if (!gloss.text && !rows.length) return undefined; if (rows.length) { rows.sort(function (a, b) { var aLang = langsByCode[a[0]] || {}; var bLang = langsByCode[b[0]] || {}; return (aLang.sortKey || "").localeCompare(bLang.sortKey || "", "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"); if (!wordLines) return undefined; var block = "{{werger-ser|" + (gloss.text || "?") + "|" + gloss.index + "}}"; block += "\n" + wordLines; block += "\n{{werger-bin}}"; return block; }); if (!blocks.length) return ""; return "\n==== Bi zaravayên din ====\n" + blocks.join("\n") + "\n"; } }, trans: { id: "trans", name: "werger", question_fmt: "Wergera vê maneyê bi zimanên din binivîse", visible: function (values) { if (!(values.lang === "ku" && values.pos)) return false; // Hide only when every sense is a filled template sense (no plain // gloss to attach translations to). A mix, or nothing filled in // yet, still shows Werger. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRealSense = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); var hasFilledTplSense = dfnSenses.some(function (s) { return s.tpl && s.tplTitle; }); return hasRealSense || !hasFilledTplSense; }, disabledKeys: { "navz": true, "ku": true, "ckb": true, "sdh": true, "lki": true, "hac": true, "zza": true }, // Language dropdown + growing word-input list, scoped to one gloss's // group (each gloss has its own group and row list). buildRow: function (group) { var row = $("<li class='wiktku-trans-row wiktku-lang-row'></li>"); // Language selector — the searchable picker 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)); // The searchable picker is attached by initSelects() once the row // is in the DOM (see onLangChange/buildGroup below). 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); // Attach the searchable picker now the row is in the DOM. initSelects(newRow); } // 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("wiktku:refresh"); }); }, // Builds (or fetches) the .wiktku-trans-group for one gloss. 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); // Attach the searchable picker now the select is in the DOM. initSelects(list); return group; }, // Syncs one .wiktku-trans-group per current gloss, keyed by // data-gloss-pos so groups stay matched across rebuilds. 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, grouped by gloss position. 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 per dfn sense // with a real mane (skips template senses). index is 1-based and // matches the sense's position in the "#" definition list. // When nothing's filled in, returns one placeholder entry so // Werger still has a group to attach to; when every sense is a // filled template sense, stays empty (matches trans.visible()). 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) { // No mane, but other fields are filled — still gets a // gloss group since dfn.getOutput() emits {{mane?}} for it. if (senseHasExtraContent(s)) glosses.push({ index: i + 1, text: "" }); return; } if (dfn[0] !== dfn[0].toLowerCase()) dfn = decapitalize(dfn); dfn = stripWikilinks(dfn).replace(/[.…?!)\]،؟]+$/, ""); glosses.push({ index: i + 1, text: 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 ""; // A completely empty entry (nothing filled in dfn at all, no // şablon chosen either) still gets a placeholder Werger section // to fill in later — same reasoning as Etîmolojî's {{ji?}}. Only // skip an individual placeholder gloss below when some other // sense actually has real content, making that particular // placeholder redundant. var dfnSenses = steps.dfn.getSenses($("#wiktku-start-dfn")); var hasRegularMane = dfnSenses.some(function (s) { return !s.tpl && (s.mane !== "" || senseHasExtraContent(s)); }); // 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. If some other sense already has real // content, this placeholder is redundant — skip it. If the // whole entry is empty, keep it so Werger still gets a // section to fill in. if (!gloss.text && !rows.length && hasRegularMane) 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.sortKey || "").localeCompare(bLang.sortKey || "", "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"; } }, cavkani: { id: "cavkani", name: "çavkanî", question_fmt: "Çavkaniyên din ên (ne jêgirtinan) lê zêde bike", visible: function (values) { return !!values.pos; }, // Fills the insert-dropdown from the members of [[Kategorî:Çavkanî]]. refreshTplSelect: function () { var sel = $("#wiktku-start-cavkani .wiktku-tpl-insert-select"); if (!sel.length) return; sel.find("option[value!='']").remove(); $.each(catSrcTemplates || [], function (_, name) { sel.append($("<option></option>").val(name).text(name)); }); // Tell the picker the option list changed. sel.trigger("wiktku:refresh"); }, build: function (stepDiv) { if (stepDiv.find(".wiktku-cavkani-wrap").length) return null; var wrap = $("<div class='wiktku-cavkani-wrap'></div>"); var ta = $("<textarea></textarea>") .attr("name", "wiktku-cavkani-" + $.now()) .attr("class", "wiktku-start-step-field wiktku-cavkani-text") .attr("rows", 4) .attr("placeholder", "Şablonekî ji jêrê hilbijêre an rasterast binivîse…"); // Template insert dropdown, populated from [[Kategorî:Çavkanî]] — // options refreshed once the category members are fetched. var sel = $("<select class='wiktku-tpl-insert-select'></select>"); sel.attr("data-placeholder", "Şablonek lê zêde bike…"); sel.append($("<option value=''>— şablonek lê zêde bike —</option>")); var status = $("<span class='wiktku-cavkani-status'></span>"); sel.on("change", function () { var name = $(this).val(); if (!name) return; insertAtCursor(ta[0], "\n* {{" + name + "}}"); $(this).val(""); sel.trigger("wiktku:refresh"); ta.focus(); }); wrap.append(sel); wrap.append(status).append(ta); stepDiv.append(wrap); // build() runs again for every new beş (see the "+ Beş zêde bike" // handler), after the initial page-wide pass — so this select needs // its own init or it stays a plain, unsearchable native <select>. initSelects(wrap); // Populate only now: refreshTplSelect() looks the select up by id // under #wiktku-start-cavkani, so running it before the wrap was // appended found nothing and bailed out — which left the dropdown // empty on every beş after the first, once the category members // were already cached. if (catSrcTemplates) { steps.cavkani.refreshTplSelect(); } else { status.text("Şablon tên barkirin…"); fetchCatSrcTemplates().then(function () { steps.cavkani.refreshTplSelect(); status.text(""); }, function () { status.text("Şablon nehatin barkirin."); }); } return ta; }, output: function () { var text = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-text").val()); if (!text) return ""; return "\n==== Çavkanî ====\n" + text + "\n"; } }, }; steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(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.zarava, steps.trans, steps.cavkani]; // 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", "zarava", "trans", "cavkani" ]; // ── 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; function snapshotDfn() { return steps.dfn.getSenses($("#wiktku-start-dfn")); } // Rebuilds 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(""); } // dfnArea is the only thing actually saved, so split it back into // werger/îzah for editing (mirrors syncNonKuToMane's join format). var maneParts = splitWergerIzah(sense.mane); block.find(".wiktku-dfn-werger").val(maneParts ? maneParts.werger : (sense.mane || "")); block.find(".wiktku-dfn-izah").val(maneParts ? maneParts.izah : ""); // Re-sync the formên alternatîv/hevmane/… hide state now that // tplSelect's value was set programmatically (its own "change" // handler doesn't fire from .val(), so this doesn't happen otherwise). var updateVis = block.data("updateFieldVisibility"); if (updateVis) updateVis(); // Same for the mane-box mode (plain vs werger+îzah), since this // also depends on tplSelect's (and lang's) value. var updateMane = block.data("updateManeMode"); if (updateMane) updateMane(); // Restore a sub-list (etiket, formên alternatîv, 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-kategori": sense.kategori, "wiktku-dfn-alternativ": sense.alternativ, "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 entries — accepts current array shape or a legacy // single object (older saved sections) for backwards compat. 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.jederCatTpl) { // Legacy format from before the şablon search switched rows to // manual mode directly — convert it the same way now, so it's // editable like any other free-form source. var catSelEl = li.find(".wiktku-dfn-quote-src-sel"); catSelEl.val("__manual__").trigger("change"); li.find(".wiktku-dfn-quote-src-manual").val("{{" + j.jederCatTpl + "}}"); } 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()); } }); } // Snapshots simple (non-dfn) per-section steps from the 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; } if (id === "cavkani") { snap.cavkani = $.trim($("#wiktku-start-cavkani .wiktku-cavkani-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 === "zarava") { snap.zarava = steps.zarava.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; } // Restores 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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); $("#wiktku-start-cavkani .wiktku-cavkani-text").val(snap.cavkani || ""); 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 === "zarava") { // Rebuild zarava groups (dfn must already be restored by this // point in the $.each loop, so glossList() reflects it). var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-group").remove(); steps.zarava.build(zaravaDiv); var zaravaGroupsSnap = snap.zarava || []; $.each(zaravaGroupsSnap, function (gi, rows) { var group = zaravaDiv.find(".wiktku-zarava-group[data-gloss-pos='" + gi + "']"); if (!group.length) return; // gloss no longer exists — drop its rows var list = group.find("ul.wiktku-zarava-list"); $.each(rows, function (j, row) { var lang = row[0], words = row[1]; var lastRow = list.find("li.wiktku-zarava-row").last(); lastRow.find("select").val(lang).trigger("change"); var wordList = lastRow.find("ul.wiktku-zarava-words"); $.each(words, function (k, word) { var wordItems = wordList.find("li"); if (k < wordItems.length) { wordItems.eq(k).find("textarea").val(word); } else { var extraInput = steps.zarava.makeWordInput(); wordList.append($("<li></li>").append(extraInput)); extraInput.val(word); } }); if ($.trim(wordList.children("li").last().find("textarea").val())) { wordList.append($("<li></li>").append(steps.zarava.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); } // Tell the pickers about the programmatic value change. fields.filter("select").trigger("wiktku:refresh"); }); } 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.zarava.output(values); entry += steps.trans.output(values); entry += steps.cavkani.output(values); callback(entry, values); }); } 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); } // Assembles wikitext for all sections plus the shared lang/pron 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; var summaryField = document.getElementById("wpSummary"); if (addLangMode && summaryField.value) { summary = summaryField.value + " " + summary; } summaryField.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 () { 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, placeholderText) { if (!disabledValues) disabledValues = {}; var vals = inputs.map(function (i, input) { return $(input).val(); }); inputs.empty(); inputs.append($("<option></option>").text(placeholderText || "")); $.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.label); if (choice.sortKey !== undefined) { // This is a language choice {code, label, sortKey} — show code. displayText = capitalize(choice.label) + " (" + choice.code + ")"; } var option = $(mw.html.element("option", { value: choice.code }, displayText)); if (disabledValues[choice.code]) option.prop("disabled", true); inputs.append(option); }); inputs.val(function (i) { return vals[i]; }); } // Keys to disable for a key menu: already-taken or explicitly disabled. function getDisabledKeys(step) { var occupiedKeys = {}; $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield").each(function () { 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); populateMenus(input, step.keys, getDisabledKeys(step)); // Keep the key menus mutually exclusive: whatever one row selects is // disabled in every other row. Recomputed from the DOM on each change. input.on("change", function () { var all = $("#wiktku-start-" + step.id + " .wiktku-start-step-keyfield"); var taken = {}; all.each(function () { var v = $(this).val(); if (v) taken[v] = true; }); all.not(this).each(function () { var self = $(this), own = self.val(); self.find("option").each(function () { var code = $(this).val(); if (code) $(this).prop("disabled", !!taken[code] && code !== own); }); self.trigger("wiktku:refresh"); }); }); // Return the wrapper; the select lives inside it and still fires change. return wrapNativeSelect(input); } // Adds another text field to the list if the last one now has text. 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); if (step.placeholder) nextInput.attr("placeholder", step.placeholder); 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) initSelects(nextItem); } var canContinue = !continueBtn.isDisabled(); 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/hides 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(); steps.cavkani.refreshTplSelect(); // Re-render any step's question label that depends on current values // (e.g. dfn's Werger-section reminder, which only applies to ku). $.each(steps, function (stepId, step) { if (typeof step.question_fmt === "function") { $("#wiktku-start-" + stepId + " .wiktku-start-step-question") .text(step.question_fmt(values)); } }); // Sync every sense block's mane-box mode (plain mane vs werger+îzah) // to the current language, in case lang changes after blocks exist. $("#wiktku-start-dfn li.wiktku-dfn-sense").each(function () { var updateMane = $(this).data("updateManeMode"); if (updateMane) updateMane(); }); // 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); // 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", "Tercimeya nimûneyê 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ê ya 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(); } 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) { // wrapNativeSelect() hides the real <select> and shows a // proxy search box in its place, so focusing `input` // directly (the hidden select) does nothing visible and // browsers won't scroll to it -- that's why the step // looked "invisible" and had to be found by scrolling. // Focus whichever of the two is actually on screen. var focusTarget = input.is(":visible") ? input : input.closest(".wiktku-native-select-wrap").find(".wiktku-ac-input"); if (!focusTarget.length) focusTarget = input; // Belt-and-suspenders: explicitly scroll the step into // view rather than relying on focus()'s scroll-into-view // behaviour, which mobile browsers apply inconsistently // right after a slideDown animation. var stepEl = stepDiv.get(0); if (stepEl && typeof stepEl.scrollIntoView === "function") { stepEl.scrollIntoView({ behavior: "smooth", block: "start" }); } focusTarget.focus(); }; didFocus = true; } stepDiv.slideDown(didSlideDown); } if (step.required && (values[stepId] === "" || (step.multiple && values[stepId].join("") === ""))) { canContinue = false; } }); continueBtn.setDisabled(!canContinue); } function destroy() { $("#wiktku-start-form, .noafterwizard").slideUp(function () { $(this).remove(); }); $(".noarticletext .nowizard, #editform").slideDown(); $("#ca-edit").removeClass("selected"); $("#ca-wiktku-nowizard").addClass("selected"); } // Priority order for Kurdish dialects and the navz pseudo-code. // Codes listed here come before all other languages; unlisted codes // are sorted alphabetically by their display name via localeCompare. var LANG_PRIORITY = ["navz", "ku", "hac", "sdh", "lki", "ckb", "zza"]; // Inserts a new "== {{ziman|code}} ==" section at the correct sorted // position: navz, then ku/hac/sdh/lki/ckb/zza, then alphabetical by name. function insertNewLangSection(existing, wikitext) { var newCodeMatch = wikitext.match(new RegExp("^" + langHeaderSource("[^}]+"))); var newCode = newCodeMatch ? newCodeMatch[1] : ""; var sections = []; var preamble = ""; var anyHeaderSrc = langHeaderSource("[^}]+"); var firstMatch = new RegExp("^" + anyHeaderSrc, "m").exec(existing); if (!firstMatch) { // No existing lang sections at all — just append. var sep = existing && !/\n\s*$/.test(existing) ? "\n\n" : ""; return existing + sep + wikitext; } // Everything before the first == {{ziman|...}} == is the preamble. var firstSectionStart = firstMatch.index; // Walk back to the start of that line. var lineStart = existing.lastIndexOf("\n", firstSectionStart - 1); var preambleEnd = lineStart !== -1 ? lineStart + 1 : 0; preamble = existing.slice(0, preambleEnd); // Parse each language section: header line + everything until the next header. var body = existing.slice(preambleEnd); // (?![\s\S]) matches only true end-of-string, since a bare "$" with // /m would stop at the section's first line break instead. var langSectionRe = new RegExp( "^(" + anyHeaderSrc + "\\n?)([\\s\\S]*?)(?=\\n" + anyHeaderSrc + "|(?![\\s\\S]))", "gm" ); var m; while ((m = langSectionRe.exec(body)) !== null) { sections.push({ code: m[2], content: m[0] // full text of this section including header }); } // Determine sort rank: priority list first (by index), then alphabetical. function getLangName(code) { var entry = langsByCode[code]; return entry ? entry.label : code; } function sortRank(code) { var idx = LANG_PRIORITY.indexOf(code); return idx !== -1 ? idx : LANG_PRIORITY.length; } function compareLangs(a, b) { var ra = sortRank(a), rb = sortRank(b); if (ra !== rb) return ra - rb; // Both are outside priority list — sort by display name. return getLangName(a).localeCompare(getLangName(b), userLang); } // Insert the new section into the sorted list. var newSection = { code: newCode, content: wikitext }; var inserted = false; for (var i = 0; i < sections.length; i++) { if (compareLangs(newCode, sections[i].code) < 0) { sections.splice(i, 0, newSection); inserted = true; break; } } if (!inserted) sections.push(newSection); // Re-join: preamble + sections separated by newlines. var joined = sections.map(function (s) { // Ensure each section ends with exactly one newline before the next. return s.content.replace(/\n+$/, ""); }).join("\n"); return preamble + joined + "\n"; } 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(); }); if (callToAction.length) { 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 clearPageCheck = null; if (addLangMode) { startForm.append($("<p class='wiktku-addlang-notice'></p>").html( "Bi vê formê tu yê zimanekî nû li rûpelê îlawe bikî. Eger ev zimanê jixwe di rûpelê de hebe, beşa nû li dawiya vî zimanî dê were îlawekirin. " + "Ji kerema xwe netîceya dawî kontrol bike, eger problemek derkeve, li <a href='" + mw.util.getUrl('Mediawiki talk:Gadget-start.js') + "'>nîqaşa vê amûrê</a> problemê ragihîne." )); clearPageCheck = $("<input type='checkbox' id='wiktku-clear-page-check'>"); var clearPageLabel = $("<label for='wiktku-clear-page-check'></label>") .text(" Naveroka rûpelê paqij bike (rûpelê ji nû ve binivîse)"); startForm.append( $("<p class='wiktku-addlang-notice'></p>") .append(clearPageCheck) .append(clearPageLabel) ); // Re-evaluate step visibility (e.g. the pron step) whenever this // is toggled, since it changes what counts as "existing content". clearPageCheck.on("change", function () { refresh(); }); } var spinner; // Tab bar for switching between POS sections. var sectionTabsDiv = $("<div id='wiktku-section-tabs'></div>"); startForm.submit(function (evt) { evt.preventDefault(); continueBtn.setDisabled(true); continueBtn.$element.addClass("wiktku-btn-sending"); spinner.show(); getWikitext(function (wikitext) { if (addLangMode && clearPageCheck && clearPageCheck.prop("checked")) { // User asked to wipe the page and start fresh — just // write the newly generated wikitext as the full content. $("#wpTextbox1").val(wikitext); } else if (addLangMode) { var textbox = $("#wpTextbox1"); var existing = textbox.val() || ""; // If this language's section already exists (whitespace // differences aside), merge into it; otherwise insert new. var langHeaderMatch = wikitext.match(new RegExp("^(" + langHeaderSource("[^}]+") + "\\n)")); if (langHeaderMatch) { var langHeader = langHeaderMatch[1]; // e.g. "== {{ziman|ku}} ==\n" var newCode = langHeaderMatch[2]; var existingHeader = findLangHeader(existing, newCode); if (existingHeader) { // Strip the header from the new output. var newContent = wikitext.slice(langHeader.length); // Find the insertion point: end of the existing lang section. // A new L2 heading marks the start of the next language block. var searchFrom = existingHeader.index + existingHeader.match.length; // Find the next == … == heading after this section's start. var nextL2 = existing.indexOf("\n== ", searchFrom); var insertAt = nextL2 !== -1 ? nextL2 : existing.length; // Ensure there's a blank line before the inserted block. var before = existing.slice(0, insertAt); var after = existing.slice(insertAt); var sep = /\n\s*$/.test(before) ? "" : "\n"; textbox.val(before + sep + newContent + after); } else { // New language — insert at the correct sorted position. textbox.val(insertNewLangSection(existing, wikitext)); } } else { // Unexpected format — insert at sorted position anyway. textbox.val(insertNewLangSection(existing, wikitext)); } } else { $("#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) { // question_fmt can be a plain string, or a function of the // current values (used by steps whose question text depends // on e.g. the chosen language) — refresh() keeps it in sync // afterwards via the .wiktku-start-step-question class. var questionText = typeof step.question_fmt === "function" ? step.question_fmt(getValues()) : step.question_fmt; stepDiv.append($(mw.html.element("label", { "class": "wiktku-start-step-question", "for": "wiktku-start-" + step.id + "-field" }, questionText))); if (step.question_br) stepDiv.append($("<br>")); } var input; 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); // initSelects() runs over the whole form once it is in the DOM. stepDiv.append(input); } else if (typeof(step.build) === "function") { input = step.build(stepDiv); } 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.placeholder) input.attr("placeholder", step.placeholder); 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 ────────────────────────────────────────────── // ── Add-section button — lives in the tab bar, disabled until pos chosen ── var addSectionBtn = new OO.ui.ButtonWidget({ label: "+ Beş zêde bike", disabled: true }); addSectionBtn.on("click", function () { saveCurrentSection(); sections.push({}); activeSection = sections.length - 1; $.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 === "cavkani") { $("#wiktku-start-cavkani .wiktku-cavkani-wrap").remove(); steps.cavkani.build($("#wiktku-start-cavkani")); return; } if (id === "trans") { var transDiv = $("#wiktku-start-trans"); transDiv.find(".wiktku-trans-group").remove(); return; } if (id === "zarava") { var zaravaDiv = $("#wiktku-start-zarava"); zaravaDiv.find(".wiktku-zarava-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(""); stepDiv.find("select.wiktku-start-step-field").trigger("wiktku:refresh"); }); renderSectionTabs(); refresh(); $("html, body").animate({ scrollTop: sectionTabsDiv.offset().top - 20 }, 300); }); /** Re-render the tab bar to reflect current sections[] and activeSection. */ function renderSectionTabs() { // Detach (not remove) the button first: .empty() strips bound // event data from any children left inside it, which would // silently kill addSectionBtn's click handler on every re-render. addSectionBtn.$element.detach(); sectionTabsDiv.empty(); var lang = getValues().lang || ""; if (!lang) { sectionTabsDiv.hide(); return; } sectionTabsDiv.show(); $.each(sections, function (i) { 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); }); // Enable "Beş zêde bike" only when the active section has a pos chosen. var activePos = sections[activeSection] && sections[activeSection].pos ? sections[activeSection].pos : getValues().pos; addSectionBtn.setDisabled(!activePos); sectionTabsDiv.append(addSectionBtn.$element); } renderSectionTabs(); /** * Restores a full cached draft: shared lang/pron fields, then every * section (via the same restoreSection()/refresh()/renderSectionTabs() * sequence already used when switching tabs). * @param cached {{lang: string, pron: string, sections: Array, activeSection: number}} */ function restoreFromCache(cached) { if (cached.lang) { $("#wiktku-start-lang-field").val(cached.lang); $("#wiktku-start-lang-field").trigger("wiktku:refresh"); } // Rebuild dependent steps (pos, pron wrap, etc.) now that lang is set. refresh(); if (cached.pron !== undefined) { $("#wiktku-start-pron .wiktku-pron-text").val(cached.pron); } sections = (cached.sections && cached.sections.length) ? cached.sections : [{}]; activeSection = (typeof cached.activeSection === "number" && cached.activeSection >= 0 && cached.activeSection < sections.length) ? cached.activeSection : 0; restoreSection(sections[activeSection]); refresh(); renderSectionTabs(); mw.notify("Danûstandina berê ya tomarkirî ji cache hate barkirin.", { type: "info", tag: "wiktku-cache-restore" }); } // 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 = new OO.ui.ButtonWidget({ id: "wiktku-unhide-editform", label: "Bişîne", flags: [ "primary", "progressive" ] }); continueBtn.on("click", function () { // Immediate, unmissable feedback that the click registered — // the mw.notify toast alone is easy to miss, and the button's // disabled state (set later, inside the submit handler once // getWikitext resolves) can take a moment to kick in. continueBtn.$element.addClass("wiktku-btn-flash"); setTimeout(function () { continueBtn.$element.removeClass("wiktku-btn-flash"); }, 500); continueBtn.setLabel("Tê şandin…"); mw.notify("Tê şandin…", { type: "info", tag: "wiktku-submit" }); startForm.trigger("submit"); }); footer.append(continueBtn.$element); // "Edîtora çavkaniyê veke" button — inline fallback for the portlet link // which is invisible on mobile and easy to miss on desktop. var sourceEditorBtn = new OO.ui.ButtonWidget({ label: "Edîtora çavkaniyê veke" }); sourceEditorBtn.on("click", function () { destroy(); }); footer.append(sourceEditorBtn.$element); // ── Cache save/clear buttons ───────────────────────────────────────── // Manual, page-scoped save of the entire wizard (all sections, not // just the active one) via [[MediaWiki:Gadget-StorageUtils.js]]'s // ObjectStorage. Restoring happens silently on load (see the // ziman.json .then() callback below), once the full language list // is available. var saveCacheBtn = new OO.ui.ButtonWidget({ label: "Li cache tomar bike", title: "Rewşa niha ya vê formê (ziman, bilêvkirin û hemû beş) li cache (localStorage) tomar bike, da ku eger rûpel bêyî xwestin were girtin an ji nû ve were barkirin, tu karibî berdewam bikî." }); saveCacheBtn.on("click", function () { saveCurrentSection(); var snapshot = { lang: getValues().lang || "", pron: $("#wiktku-start-pron .wiktku-pron-text").val() || "", sections: sections, activeSection: activeSection }; // ObjectStorage.Set() doesn't return a success/failure value, so // the only way to detect a real failure (storage blocked, quota // exceeded, JSON.stringify choking on something unexpected) is to // catch it here rather than inspect a (nonexistent) return value. try { formCache.Set(snapshot); mw.notify("Rewşa formê li cache hate tomarkirin.", { type: "success", tag: "wiktku-cache-save" }); } catch (e) { mw.notify("Tomarkirina li cache serneket.", { type: "error", tag: "wiktku-cache-save" }); } }); footer.append(saveCacheBtn.$element); var clearCacheBtn = new OO.ui.ButtonWidget({ label: "Cache paqij bike", flags: [ "destructive" ], title: "Daneyên tomarkirî yên vê rûpelê ji cache jê bibe (formeke ku niha xuya dike naguherîne)." }); clearCacheBtn.on("click", function () { formCache.Set({}); mw.notify("Cache hate paqijkirin.", { type: "success", tag: "wiktku-cache-clear" }); }); footer.append(clearCacheBtn.$element); // ── 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; var livePreviewActive = false; // guards in-flight fetches after uncheck /** 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) { // Discard result if the user unchecked while the fetch was in flight. if (!livePreviewActive) return; 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 — only touch panels that are // actually shown so that setting flex doesn't override display:none. if (wikitextVisible) previewPanel.css({ "flex": "1 1 100%", "min-width": "" }); if (liveVisible && 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")) { livePreviewActive = true; livePreviewPanel.show(); loadLivePreview(); livePreviewIntervalId = setInterval(loadLivePreview, 500); } else { livePreviewActive = false; 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); // One pass over the whole form: every select that hasn't already been // initialised, and isn't opted out with .wiktku-plain-select, gets // the searchable picker. initSelects(startForm); 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.code; }); zimanJsonPromise.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: code, label: name, sortKey: sortKey }; extraChoices.push(choice); langsByCode[code] = choice; }); // Populate langsByCode for pinned choices too. $.each(pinnedChoices, function (i, choice) { // Ensure pinned choices have a sortKey. if (choice.sortKey === undefined) choice.sortKey = choice.label; langsByCode[choice.code] = choice; }); // Sort the extra choices alphabetically by sort key. extraChoices.sort(function (a, b) { return a.sortKey.localeCompare(b.sortKey, 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; steps.zarava.keys = getZaravaKeys(allChoices); // Replacing the option list only needs a wiktku:refresh so each // picker re-reads its <option>s. var langMenu = $("#wiktku-start-lang-field"); populateMenus(langMenu, steps.lang.choices); langMenu.trigger("wiktku:refresh"); var transMenus = $("#wiktku-start-trans .wiktku-start-step-keyfield"); populateMenus(transMenus, steps.trans.keys, getDisabledKeys(steps.trans)); transMenus.trigger("wiktku:refresh"); var dundeMenus = $("#wiktku-start-dunde .wiktku-start-step-keyfield"); populateMenus(dundeMenus, steps.dunde.keys, getDisabledKeys(steps.dunde)); dundeMenus.trigger("wiktku:refresh"); var zaravaMenus = $("#wiktku-start-zarava .wiktku-start-step-keyfield"); populateMenus(zaravaMenus, steps.zarava.keys, getDisabledKeys(steps.zarava)); // Was missing entirely: without this the Zarava picker kept serving the // option list it cached before ziman.json replaced it. zaravaMenus.trigger("wiktku:refresh"); // Now that the full language list is loaded, silently restore any // draft the editor previously saved for this page (if the "Li // cache tomar bike" button was ever used here). var cachedDraft = formCache.Get(); if (cachedDraft && cachedDraft.sections && cachedDraft.sections.length) { restoreFromCache(cachedDraft); } }); } // oojs-ui-core loads in parallel with metaApiPromise above (mediawiki.api // + the two API requests) — this block only needs to wait on it. // jquery.chosen is deliberately not loaded: the form has one dropdown // implementation now (wrapNativeSelect). mw.loader.using(["oojs-ui-core"], function () { // Load metadata, langChoices, posChoices and tplDefs from the companion // data page so they can be updated without touching this script. // (Request was already fired via metaApiPromise above, in parallel // with this module load — we're just picking up the result here.) metaApiPromise.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 gender labels. if (d.genderLabels) $.extend(GENDER_BASE_LABELS, d.genderLabels); // Populate lang choices (pinned list used by build() → ziman.json loader). // data.json stores these as a plain {code: label} object. if (d.langChoices) steps.lang.choices = choicesFromObject(d.langChoices, true); // Populate POS choices — also a plain {code: label} object in data.json. if (d.posChoices) steps.pos.choices = choicesFromObject(d.posChoices, false); // 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/zarava keys with the (now populated) lang choices. steps.trans.keys = steps.lang.choices; steps.dunde.keys = steps.lang.choices; steps.zarava.keys = getZaravaKeys(steps.lang.choices); }).always(build); }); }); //</nowiki> n7ohnoqwo2ugq80kdeva3tw483yupc1 MediaWiki:Gadget-aWa.js/belgekirin 8 1240222 6291775 5609765 2026-07-28T01:47:43Z Wikihez 7344 6291775 wikitext text/x-wiki * Ji bo aktîvkirina vê amûrê here [[Special:Preferences#mw-prefsection-gadgets|beşa Amûr a "Tercîhên min"]] û qutiya li gel [[File:UnclickedCheckbox.jpg|ClickedCheckbox.jpg]] {{int:gadget-aWa}} :bitikîne. bscchlliv3bvbo6mhig2jcn3mgzjsad Wîkîferheng:Dîwan/2026 4 1327120 6291767 6291501 2026-07-28T00:17:00Z Ghybu 1393 /* mê yan nêr li gorî maneyê / mê yan nêr (bikaranîn dudil e) */ beşeke nû 6291767 wikitext text/x-wiki <noinclude>{{Dîwan/arşîv-ser|2026}}</noinclude> {{clear}} == Daxwazên standardkirinê == https://ku.wiktionary.org/wiki/W%C3%AEk%C3%AEferheng:Daxwaz%C3%AAn_standardkirin%C3%AA, Gelo di vê malperê de peyvên hatîye standart kirin; ji malperê rakin? Zêde tehlîhev e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:03, 8 kanûna paşîn 2026 (UTC) :@[[Bikarhêner:Rewiye tine|Rewiye tine]] [[Taybet:Tercîh#mw-prefsection-gadgets]] li vir amûra [[MediaWiki:Gadget-aWa.js/belgekirin|awa]] aktîv bike û pê re dikarî gotûbêjan arşîv bikî. Li sayfa [[WF:DS]] li kêleka her sernavê gotûbêjê <nowiki>[arşîv bike]</nowiki> derdikeve, pê lê bike û ew ê arşîv bike. Eger nikarî tu tenê şablona {{ş|ds-kirî}} îlawe bike, ez ê dûre arşîv bikim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:35, 5 tîrmeh 2026 (UTC) == Standartkirin == Sala borî, min pêşnîyazek kiribû. Halî hazir piştî daxwaza standarkirinê em du heftî disekinin, eger kesek fikrek dîyar neke. Raste rast peyv li gor ferhenga standart a mezopotamyayê tê standart kirin. Ji xwe sazîyek vê karî dike çima em vê barî dikin stuyê xwe. Mesela ez çaxe di wîkîferhengê de peyvek digêrim; standart a peyvê jî li cem xwe kontrol dikim. Eger destûr hebe bi germî dikarim wê malperê standart bikim. Benda bûna du heftîyan gelo ne zehmet e? Duyemîn pêşnîyaza min nîşandana standarta peyvê di malpera de ye. Kesek dema malperan binêre, divê li jora malperan bibîne ku ev peyv standart e. Ev jî hîzmet e. Çimkî nivîskar, wergêr, edîtor, rojnemavan hez dikin bi peyvê standart binivîsin. https://ku.wiktionary.org/wiki/k%C3%AAf li vir wekî mînak min daye nîşan. Lê îfade eger wisa be: Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r. 253) e yê çetir be. Çimkî îfadeya berê de peyva kurdî-tirkî derbas dibe û di mejîyê mirov de tevlihevî çêdibe.@[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:25, 8 kanûna paşîn 2026 (UTC) :Merheba. Hevalno dîyar e karê standarkirinê li wîkîferhengê rawestîya ye. Min sê peyv ji bo standartkirinê qeyd kir. Kes li ser şîrove nenivîsî. Mehek jî li ser derbas bû. Aniha ez dikarim van rupelan biguherim. Li gor qaîdeya hatine danîn wisa ye. Daxwaza min heta niha jî ew e kelîmeyên di ferhenga standartkirinê de heyî divê em bikaribin rasterast li vir jî bikin standart. An jî demê kurttir bikin. Li weqfa mezapotamyayê 20 mirov digêhin hev li ser peyvekî seetan nîqaş dikin. Ma hewceyê em jî li vir nîqaş bikin? Tevlî vê jî ji xwe kes li ser vê mijare nasekîne van dema. Xeynî vê pêşnîyaza min nîşandana standarta peyvê di malpera de hebû. Li ser malperê 'Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r.253) e' Tiştek mîna wî hebe yê gelek kêrî her cure nivîskarê me were. Çimkî hin nivîskarên me hez dike bi kelîmeyên standart binivîse. Di malperê de bila vê hêsanî fam bike çêtir e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Ghybu|Ghybu]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 18:35, 17 sibat 2026 (UTC) ::Merheba @[[Bikarhêner:Rewiye tine|Rewiye tine]]. Ev format pir xirab dibe. Tu dikarî li beşa Çavkaniyê binivîsî bi şablona {{ş|kitêb}} binivîsî çêtir e û tê eynî maneyê. Lê her kes standarda Weqfa Mezopotamyayê qebûl nakin û ez jî şibhê dikim ku ev websîte bi awayekî kolektîv tê çêkirin an na. Loma em bi ya kitêba rastnivisînê çêkin û eger îtîraz tinebe, şablona {{ş|ds-kirî}} li gotûbêja [[WF:DS]] binivîse, dûre li gotûbêjê arşîv bike, ne hewce ye li hêviya kesên din bisekinî. Eger itirazek hebe, ê ku dixwaze dûre dîsa şablona ds zêde bike. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:30, 5 tîrmeh 2026 (UTC) :::[https://berwarnews.com/ferhenga-rastnivisine-qonaxeke-giring-a-standardkirina-kurmanci-ye/ Roportaja Mikail Bülbül] li ser proseya standardkirinê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:57, 9 tîrmeh 2026 (UTC) ::::Min nû dît an jî nû hatiye zêdekirin lê meqaleyek bi navê [https://www.ferhengkurdi.com/?q=iltihap&modal=lijne lijneya edîtorîyê] nivîsandine [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:40, 22 tîrmeh 2026 (UTC) == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 kanûna paşîn 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Bikarhêner:MediaWiki message delivery|MediaWiki message delivery]] ([[Gotûbêja bikarhêner:MediaWiki message delivery|gotûbêj]]) 00:58, 26 nîsan 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == Guharto == : <small>→ Ji rûpela ''[//ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAj:berf%C3%AEtik&oldid=6233338 Gotûbêj:berfîtik]'' hatiye girtin.</small> Silav {{r|Ghybu}} ma hewce ye em guhartoyan jî kategorîze bikin? Li vê [[ژیشک]] binere, tije guhartoyên wê hene, ku em ji gişan re guhandar binivîsin dê 10 navên heman hebin di nav wê kategorîyê de. Tu çi difikirî? [[Bikarhêner:Keyomerd|Keyomerd]] ([[Gotûbêja bikarhêner:Keyomerd|gotûbêj]]) 09:40, 26 nîsan 2026 (UTC) :{{silav|Keyomerd}}. Erê, problem çî ye? {{=)}} Ew jî tên bikaranîn... Dema ku peyvek tê çêkirin hewce ye ku em hemû agahiyên wan binivîsin: bilêvkirin, bikaranîn, mînak, terîm, herêm, tewandin, etîmolojî... :Bi min peyvên ku wekî ''guherto'' hatine nivîsandin bi nivîsa {{w|Italic type|îtalîk|ziman=en}} (xwahr) di nav kategoriyan de werin nişan kirin (ji bo cudakirinê). {{ping|Ferhengvan|Bikarhêner}} [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:40, 30 nîsan 2026 (UTC) ::Yên '''''nestandard''''' di kategorîyan de biferq werin nîşandan baştir e. Qene em karibin wan ji yên stadard ferq bikin. @[[Bikarhêner:Ghybu|Ghybu]] Xêra xwe hûn sîstemeke wisa çêkin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:36, 1 gulan 2026 (UTC) :::Merheba @[[Bikarhêner:Keyomerd|Keyomerd]] û @[[Bikarhêner:Bikarhêner|Bikarhêner]] ev xisûsiyet jixwe di şablonên rêzimanê de heye, wextê {{param|formaalt|1}} dinivîsin, made dikeve Kategoriya [[:Kategorî:Formên alternatîv bi kurmancî]] li gorî koda zimanî jî zimanên din tê çêkirin. Hemû madeyên kurmancî bi alfabeya erebî dikevin vê kategoriyê lê nizanim ev tiştekî rast e Yan xelet e, ji bo nîşandanê min çêkiribû lê min hîn wext nedît ku nîqaşek li ser çêkim. Qaîdeyên bikaranîna vê parametreyê di wîkiya îngilîzî de jî tam ne belî ye. Du gotûbêj [https://en.wiktionary.org/wiki/Wiktionary:Requests_for_moves,_mergers_and_splits#Category:Alternative_forms_by_language] [https://en.wiktionary.org/wiki/Wiktionary:Beer_parlour/2024/June#Decluttering_the_altform_mess] çêkirine lê ji bo îngilîzî ev parametre nehatiye bikaranîn. Min ji bo nîşandanê niha [https://ku.wiktionary.org/w/index.php?title=bax%C3%A7%C3%AA_zarokan&diff=prev&oldid=6241372] ceriband lê bi min xelet e. Em çawa bikin? Kengî vê parametreyê bi kar bînin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:29, 8 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Tu çi difikirî? Ji bo zazakî [https://ku.wiktionary.org/w/index.php?title=a_c%C4%B1_geyrayene&oldid=6241396 wisa] bikin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:55, 8 tîrmeh 2026 (UTC) :::::Kategorîyekê cuda baş dibe. Wextê ku ez li kategorîya "lekêren bi zazakî" dinêrim, ez hem formê bi şikilê Johnsonê û formê standardê dibînim. Zaten wexte ku ez dikevim ê Johnsonê, min dibe formê standardê. Kategorîyekê cuda, bi taybetî ji bo nivîsandinên alternatîf, baş dibe. :::::Lê em bîr nekin ku wextê ku em bo formên alternatîf yên devokî qal dikin, belkî adil neye ku em ev bişînin derekê din yê ku însan ewqas nabînin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:03, 8 tîrmeh 2026 (UTC) ::::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Gelo min rast fêm kir? Tu dibêjî formên {{q|ku|kîvroşk}} bi dîqet werin guhartokirin lê bi yên bi alfabeya Jacobsonê hemû bikin {{param|formaalt|1}}? Formên Jacobsonê dê bikevin Kategoriya [[:Kategorî:Lêker bi zazakî|Lêker bi zazakî]] û [[:Kategorî:Lema bi zazakî|Lema bi zazakî]] yan na? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:55, 8 tîrmeh 2026 (UTC) :::::::Bi min naxwaze di wan kategoriyan de bikeve. Wek tu dibînî dûplîkat pir hene. Bi min çareya baştir yên Johnsonê di katehgorîyekê din bikevin (bila format li rûpelan neyin guherandin, bi tenê kategorî) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 00:37, 9 tîrmeh 2026 (UTC) == Peyvên soranî bi latînî ([[:Kategorî:Soranî]]) == Silav, di nav vê kategoriyê (''[[:Kategorî:Soranî]]'') de pirr peyv tenê bi alfabeya latînî hatine nivîsandin. Divê ew mutleq jî bi alfabeya erebî werin transkrîbe kirin ji ber ku soranî bi alfabeya erebî tê nivîsand... Bikarênerên ku soranî dizanin dikarin wan sererast bikin? Mînakên guhertinan: [//ku.wiktionary.org/w/index.php?title=zor%C3%AEne&curid=6584&diff=6233355&oldid=5859303], [//ku.wiktionary.org/w/index.php?title=s%C3%AAw&diff=6233097&oldid=6233003], [//ku.wiktionary.org/w/index.php?title=sewz&diff=6233313&oldid=6069107], ... Spas! [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 01:16, 2 gulan 2026 (UTC) == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 gulan 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|gotûbêj]])</bdi> 17:12, 23 hezîran 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 hezîran 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Jêbirina ferhenga Sadallah == Merheba @[[Bikarhêner:Guherto|Guherto]] Îmkan heye lîsteyeke wisa çêkî ku hemû sayfeyên Cyrusbot çêkir yên ku tê de tenê tercimeyeke îngilîzî heye û ev tercime jî hatibe jêbirin? Nimûne ''[[derdzanî]], [[êşzanî]]'' tenê tercimeya [[pestology]] heye ew jî ji ber heqê telîfê hatiye jêbirin. Nimûneyeke din ''zêrrgeh'', ''zêrrkar'' [[goldsmith]] hatiye jêbirin zêr wekî zêrr hatiye guhartin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:48, 26 hezîran 2026 (UTC) == Beşa Tewandin bo kurmancî == Bi ya min şablona {{ş|ku-tewîn-nav}} û ya fiîlê em bixin beşa Tewandinê (wekî [[şodir|zazakî]]. Bi vî awayî hem ji aliyê şiklî ve hem jî ji aliyê bikaranînê ve xweştir xuya bike. Eger di qismê Tewandinê de be, ê ku dixwaze îzah û notên xwe yan jî emilandinên din jî dikare binivîse. Hûn çi dibêjin? @[[Bikarhêner:Ferhengvan|Ferhengvan]], @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:05, 6 tîrmeh 2026 (UTC) :Belkî em dikarin Formata şiweyan wekî ya behdînî jî têxin nav şablonê. Pir caran şiklê tabloya Tercimeyan ji ber dirêjbûna şablona teqînê jî xirab dibe wekî [[astrofizîk]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 6 tîrmeh 2026 (UTC) :Min mijarê te li jorê yê xwe dît, fikirên min jî hene eger baş e. Yê ku te gotiye bi min baş dibe, ji ber ku her rûpel ji vê mîna hev dibe. Em ê rindtir jî ferq li nav devokan binivîsin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:44, 7 tîrmeh 2026 (UTC) ::@[[Bikarhêner:Bikarhêner|Bikarhêner]] fikr? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:44, 15 tîrmeh 2026 (UTC) :::Formata ku te teklîf kirîye jî ne xerab e, baş tê xuyan. Feqet bi min halê berê (mewcûd) baştir e. Ji ber ku ev şablon (ku-tewîn-nav) bi piranî kurt in û ji bo her kesî ne mihîm e, lewma li kinarê bi formeke hebe ku karibe were vekirin û girtin baştir e. Lê belê ger şablon dirêjtir bin, em karin wekî ya wîkîya almanî bikin (ew jî wekî teklîfa te ye). -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 15 tîrmeh 2026 (UTC) == Reşwî == Silav ji we gî re, Pirsekê min heye. Ez difikirim şablonekê din çê bikim boy devokek kurmancî, yê êla Reşwî. Ew lêkerên xwe hinek cuda ditewînin. Mesela te hem "ez dikim" bêjî yan jî "ez dikime", "em dikinî, em tênî, te em kuştinî" (ne "em dikin") dema xwe yek in lê maneyên xwe ne yek in, "ez bikim" "ez ê bikim" "ez bikime" û dewamên xwe hemû demên xwe yek in lê mane dîsa ne yek in. Eger min çê kir, şûna xwe li ku derê tînim? Ez difikirim li tewandina devokên kurdî yê ku "tabên" xwe hene "kurmancîya rojavayî", "kurmancîya standard" hsw. Lê tewandin ewqes cuda ye dixwaze ku wî şablona tewandina kurdî pir were guherîn. Hûn çi dibêjin? (R: Hûn dewên çi?) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:38, 7 tîrmeh 2026 (UTC) :{{silav|Kurdanparez}} Binêre mînaka devoka ''rojhilatî'': [[Modul:ku-tewandin#L-135]] / [[Modul:ku-tewandin#L-138|L138]] / [[Modul:ku-tewandin#L-143|L-143]], .. Di nav modula ''ku-tewandin"-ê de tê çêkirin. [[Gotûbêja modulê:ku-tewandin#Paşgirên lêkeran di kurmanciya rojhilatî de]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:09, 7 tîrmeh 2026 (UTC) ::PS: Dema niha: [[Modul:ku-tewandin#L-128]]; dema borî: [[Modul:ku-tewandin#L-153]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:15, 7 tîrmeh 2026 (UTC) :::Merheba @[[Bikarhêner:Ghybu|Ghybu]], Eger mimkin be tu dikarî yên devokî têxî binmodulekê û bila modul load bike, bi vî awayî belkî çêkirina yên nû û famkirina modulê hêsantir be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:09, 7 tîrmeh 2026 (UTC) :::Lê di devokê reşwî de hem dema niha yê statîk heye (Îng: I do -> Ez dikim) û yê progressîf heye (I am doing -> Eîz (nêr) Ez î (mê) dikime, yan jî Ez î dikime/Ez ê dikime). Reşwî ji yê standardê pirtir bo zayend ferq tîne, hem jî li dema pêşî (Ez ê bikim (Nêr) ez a bikim (Mê)). Dema pêşî jî formên cuda hene (Ezêk bikime (I will be doing it) û ez ê/a bikim (I will do it)) :::Ev di modûlê têhel bê? [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:09, 8 tîrmeh 2026 (UTC) == WF:Xebat == Min sayfeya [[WF:Xebat]] çêkir, xeletiyên ku hûn ferq dikin ji kerema xwe lê zêde bikin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:35, 15 tîrmeh 2026 (UTC) == Modul:quote == @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]], @[[Bikarhêner:Keyomerd|Keyomerd]], @[[Bikarhêner:Ferhengvan|Ferhengvan]] Merheba, ez modula îngilîzî ya jêgirtin û çavkaniyan li gorî şablonên {{ş|jêder}} format dikim û ji bo ku hertişt wekî formata me ya niha be, gelek serê min diêşe. Ez dibêjim bila em dev ji formata niha berdin wekî ya îngilîzî bi kar bînin ji ber ku gelek xisûsiyetên îngilîzî hene ku yekî dikare biemilîne. Hûn ê bibêjin niha ji kû hat bîra tê, min got [[Wîkîferheng:Xebat#MediaWiki:Gadget-start.js|start.js]] nû bikim û min dît otomatîk çavkanî bi riya [[mw:Citoid]]ê bi riya DOI, ISBN û lînk tê çêkirin, min got wiya jî li skrîptê îlawe bikim loma min [[Wîkîferheng:Xebat#Mediawiki:Gadget-citoid-helper.js|Mediawiki:Gadget-citoid-helper.js]] hazir kir lê hin parametreyên Citoidê kêm bûn, min got ka wana rast bikim, min dît formata me ya niha ti standard bi kar nayîne tenê parametreyan bi virgulê li hev dixe. Ez dibêjim formata îngilîzî baştir e, hem ne îtalîk e ku bi hêsanî tên xwendin, hem jî tarîx û çavkanî herî pêşî tên nîşandan ku ji bo peyitandinê bo min muhîm e. Modula îngilîzî de hema bêje her tişt hatiye çêkirin, eger em rûnin tenê yên lazim li şablona çavkaniyên xwe binivîsin ew ê gelek wext bistîne. Eger em modula îngilîzî bi kar bînin, em ê hem karibin şablonên îngilîzî bi hêsanî û rast kopî bikin hem jî kurdîkirina parametreyan gelek hêsan e. Fikir? --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:20, 24 tîrmeh 2026 (UTC) : Ji bo miqayesekirinê bnr. [[:en:Template:quote-book]] / [[Şablon:jêder-kitêb/ceribandin]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:32, 24 tîrmeh 2026 (UTC) ::Bi min bila yê mewcûd jî bimîne, ew jî şiklen xweş û baştir e. Feqet bi min jî yên îngilîzî rehettir in, eger rastkirina yê mewcûd zehmet be, em rasterast wan ji xwe re bînin û tercime bikin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:41, 24 tîrmeh 2026 (UTC) :::Ez êvarê ve dixebitim, min nêzîk kiribû lê min got belkî hûn qane bibin lê xuya ye hûn ê hîn serê min gelek biêşînin {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:59, 24 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Bikarhêner|Bikarhêner]] û @[[Bikarhêner:Ghybu|Ghybu]] Eger îtîrazek tinebe, ez ê îtalîk ji jêgirtinê rakim... Jixwe bi riya [jêgirtin] dikare were veşartin û her daim bi * dest pê dike loma bi hêsanî tê fêmkirin û xwendin rihettir dibe. Bnr. [https://ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:ceribandin/nim%C3%BBne&oldid=6277132#L%C3%AAker_2 ceribandinê] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:13, 24 tîrmeh 2026 (UTC) == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 tîrmeh 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == ''mê'' yan ''nêr'' li gorî maneyê / ''mê'' yan ''nêr'' (bikaranîn dudil e) == [//ku.wiktionary.org/w/index.php?title=xelat&diff=prev&oldid=6291766]: Mixabin pirr bikarhêner şûnda parametreya <code>z=m/n</code> ('' m yan n li gorî maneyê'') <code>z=mn</code> (''m yan n (bikaranîn dudil e)'') bi kar tînin ([[Şablon:navdêr#Parametre]]) ji ber ku di nav her du nivîsê de pir ferq nebînin. Nizanim em ê dîsa parametreya <code>z=nt</code> (''nêtar'') çêkin, wekî berê: [[Wîkîferheng:Dîwan/arşîv 2019#Zayend]]. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 00:17, 28 tîrmeh 2026 (UTC) r784rvyi5p9l2n9dlt97i83jtv7cpcd 6291768 6291767 2026-07-28T00:21:12Z Ghybu 1393 /* mê yan nêr li gorî maneyê / mê yan nêr (bikaranîn dudil e) */ 6291768 wikitext text/x-wiki <noinclude>{{Dîwan/arşîv-ser|2026}}</noinclude> {{clear}} == Daxwazên standardkirinê == https://ku.wiktionary.org/wiki/W%C3%AEk%C3%AEferheng:Daxwaz%C3%AAn_standardkirin%C3%AA, Gelo di vê malperê de peyvên hatîye standart kirin; ji malperê rakin? Zêde tehlîhev e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:03, 8 kanûna paşîn 2026 (UTC) :@[[Bikarhêner:Rewiye tine|Rewiye tine]] [[Taybet:Tercîh#mw-prefsection-gadgets]] li vir amûra [[MediaWiki:Gadget-aWa.js/belgekirin|awa]] aktîv bike û pê re dikarî gotûbêjan arşîv bikî. Li sayfa [[WF:DS]] li kêleka her sernavê gotûbêjê <nowiki>[arşîv bike]</nowiki> derdikeve, pê lê bike û ew ê arşîv bike. Eger nikarî tu tenê şablona {{ş|ds-kirî}} îlawe bike, ez ê dûre arşîv bikim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:35, 5 tîrmeh 2026 (UTC) == Standartkirin == Sala borî, min pêşnîyazek kiribû. Halî hazir piştî daxwaza standarkirinê em du heftî disekinin, eger kesek fikrek dîyar neke. Raste rast peyv li gor ferhenga standart a mezopotamyayê tê standart kirin. Ji xwe sazîyek vê karî dike çima em vê barî dikin stuyê xwe. Mesela ez çaxe di wîkîferhengê de peyvek digêrim; standart a peyvê jî li cem xwe kontrol dikim. Eger destûr hebe bi germî dikarim wê malperê standart bikim. Benda bûna du heftîyan gelo ne zehmet e? Duyemîn pêşnîyaza min nîşandana standarta peyvê di malpera de ye. Kesek dema malperan binêre, divê li jora malperan bibîne ku ev peyv standart e. Ev jî hîzmet e. Çimkî nivîskar, wergêr, edîtor, rojnemavan hez dikin bi peyvê standart binivîsin. https://ku.wiktionary.org/wiki/k%C3%AAf li vir wekî mînak min daye nîşan. Lê îfade eger wisa be: Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r. 253) e yê çetir be. Çimkî îfadeya berê de peyva kurdî-tirkî derbas dibe û di mejîyê mirov de tevlihevî çêdibe.@[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:25, 8 kanûna paşîn 2026 (UTC) :Merheba. Hevalno dîyar e karê standarkirinê li wîkîferhengê rawestîya ye. Min sê peyv ji bo standartkirinê qeyd kir. Kes li ser şîrove nenivîsî. Mehek jî li ser derbas bû. Aniha ez dikarim van rupelan biguherim. Li gor qaîdeya hatine danîn wisa ye. Daxwaza min heta niha jî ew e kelîmeyên di ferhenga standartkirinê de heyî divê em bikaribin rasterast li vir jî bikin standart. An jî demê kurttir bikin. Li weqfa mezapotamyayê 20 mirov digêhin hev li ser peyvekî seetan nîqaş dikin. Ma hewceyê em jî li vir nîqaş bikin? Tevlî vê jî ji xwe kes li ser vê mijare nasekîne van dema. Xeynî vê pêşnîyaza min nîşandana standarta peyvê di malpera de hebû. Li ser malperê 'Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r.253) e' Tiştek mîna wî hebe yê gelek kêrî her cure nivîskarê me were. Çimkî hin nivîskarên me hez dike bi kelîmeyên standart binivîse. Di malperê de bila vê hêsanî fam bike çêtir e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Ghybu|Ghybu]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 18:35, 17 sibat 2026 (UTC) ::Merheba @[[Bikarhêner:Rewiye tine|Rewiye tine]]. Ev format pir xirab dibe. Tu dikarî li beşa Çavkaniyê binivîsî bi şablona {{ş|kitêb}} binivîsî çêtir e û tê eynî maneyê. Lê her kes standarda Weqfa Mezopotamyayê qebûl nakin û ez jî şibhê dikim ku ev websîte bi awayekî kolektîv tê çêkirin an na. Loma em bi ya kitêba rastnivisînê çêkin û eger îtîraz tinebe, şablona {{ş|ds-kirî}} li gotûbêja [[WF:DS]] binivîse, dûre li gotûbêjê arşîv bike, ne hewce ye li hêviya kesên din bisekinî. Eger itirazek hebe, ê ku dixwaze dûre dîsa şablona ds zêde bike. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:30, 5 tîrmeh 2026 (UTC) :::[https://berwarnews.com/ferhenga-rastnivisine-qonaxeke-giring-a-standardkirina-kurmanci-ye/ Roportaja Mikail Bülbül] li ser proseya standardkirinê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:57, 9 tîrmeh 2026 (UTC) ::::Min nû dît an jî nû hatiye zêdekirin lê meqaleyek bi navê [https://www.ferhengkurdi.com/?q=iltihap&modal=lijne lijneya edîtorîyê] nivîsandine [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:40, 22 tîrmeh 2026 (UTC) == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 kanûna paşîn 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Bikarhêner:MediaWiki message delivery|MediaWiki message delivery]] ([[Gotûbêja bikarhêner:MediaWiki message delivery|gotûbêj]]) 00:58, 26 nîsan 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == Guharto == : <small>→ Ji rûpela ''[//ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAj:berf%C3%AEtik&oldid=6233338 Gotûbêj:berfîtik]'' hatiye girtin.</small> Silav {{r|Ghybu}} ma hewce ye em guhartoyan jî kategorîze bikin? Li vê [[ژیشک]] binere, tije guhartoyên wê hene, ku em ji gişan re guhandar binivîsin dê 10 navên heman hebin di nav wê kategorîyê de. Tu çi difikirî? [[Bikarhêner:Keyomerd|Keyomerd]] ([[Gotûbêja bikarhêner:Keyomerd|gotûbêj]]) 09:40, 26 nîsan 2026 (UTC) :{{silav|Keyomerd}}. Erê, problem çî ye? {{=)}} Ew jî tên bikaranîn... Dema ku peyvek tê çêkirin hewce ye ku em hemû agahiyên wan binivîsin: bilêvkirin, bikaranîn, mînak, terîm, herêm, tewandin, etîmolojî... :Bi min peyvên ku wekî ''guherto'' hatine nivîsandin bi nivîsa {{w|Italic type|îtalîk|ziman=en}} (xwahr) di nav kategoriyan de werin nişan kirin (ji bo cudakirinê). {{ping|Ferhengvan|Bikarhêner}} [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:40, 30 nîsan 2026 (UTC) ::Yên '''''nestandard''''' di kategorîyan de biferq werin nîşandan baştir e. Qene em karibin wan ji yên stadard ferq bikin. @[[Bikarhêner:Ghybu|Ghybu]] Xêra xwe hûn sîstemeke wisa çêkin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:36, 1 gulan 2026 (UTC) :::Merheba @[[Bikarhêner:Keyomerd|Keyomerd]] û @[[Bikarhêner:Bikarhêner|Bikarhêner]] ev xisûsiyet jixwe di şablonên rêzimanê de heye, wextê {{param|formaalt|1}} dinivîsin, made dikeve Kategoriya [[:Kategorî:Formên alternatîv bi kurmancî]] li gorî koda zimanî jî zimanên din tê çêkirin. Hemû madeyên kurmancî bi alfabeya erebî dikevin vê kategoriyê lê nizanim ev tiştekî rast e Yan xelet e, ji bo nîşandanê min çêkiribû lê min hîn wext nedît ku nîqaşek li ser çêkim. Qaîdeyên bikaranîna vê parametreyê di wîkiya îngilîzî de jî tam ne belî ye. Du gotûbêj [https://en.wiktionary.org/wiki/Wiktionary:Requests_for_moves,_mergers_and_splits#Category:Alternative_forms_by_language] [https://en.wiktionary.org/wiki/Wiktionary:Beer_parlour/2024/June#Decluttering_the_altform_mess] çêkirine lê ji bo îngilîzî ev parametre nehatiye bikaranîn. Min ji bo nîşandanê niha [https://ku.wiktionary.org/w/index.php?title=bax%C3%A7%C3%AA_zarokan&diff=prev&oldid=6241372] ceriband lê bi min xelet e. Em çawa bikin? Kengî vê parametreyê bi kar bînin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:29, 8 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Tu çi difikirî? Ji bo zazakî [https://ku.wiktionary.org/w/index.php?title=a_c%C4%B1_geyrayene&oldid=6241396 wisa] bikin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:55, 8 tîrmeh 2026 (UTC) :::::Kategorîyekê cuda baş dibe. Wextê ku ez li kategorîya "lekêren bi zazakî" dinêrim, ez hem formê bi şikilê Johnsonê û formê standardê dibînim. Zaten wexte ku ez dikevim ê Johnsonê, min dibe formê standardê. Kategorîyekê cuda, bi taybetî ji bo nivîsandinên alternatîf, baş dibe. :::::Lê em bîr nekin ku wextê ku em bo formên alternatîf yên devokî qal dikin, belkî adil neye ku em ev bişînin derekê din yê ku însan ewqas nabînin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:03, 8 tîrmeh 2026 (UTC) ::::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Gelo min rast fêm kir? Tu dibêjî formên {{q|ku|kîvroşk}} bi dîqet werin guhartokirin lê bi yên bi alfabeya Jacobsonê hemû bikin {{param|formaalt|1}}? Formên Jacobsonê dê bikevin Kategoriya [[:Kategorî:Lêker bi zazakî|Lêker bi zazakî]] û [[:Kategorî:Lema bi zazakî|Lema bi zazakî]] yan na? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:55, 8 tîrmeh 2026 (UTC) :::::::Bi min naxwaze di wan kategoriyan de bikeve. Wek tu dibînî dûplîkat pir hene. Bi min çareya baştir yên Johnsonê di katehgorîyekê din bikevin (bila format li rûpelan neyin guherandin, bi tenê kategorî) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 00:37, 9 tîrmeh 2026 (UTC) == Peyvên soranî bi latînî ([[:Kategorî:Soranî]]) == Silav, di nav vê kategoriyê (''[[:Kategorî:Soranî]]'') de pirr peyv tenê bi alfabeya latînî hatine nivîsandin. Divê ew mutleq jî bi alfabeya erebî werin transkrîbe kirin ji ber ku soranî bi alfabeya erebî tê nivîsand... Bikarênerên ku soranî dizanin dikarin wan sererast bikin? Mînakên guhertinan: [//ku.wiktionary.org/w/index.php?title=zor%C3%AEne&curid=6584&diff=6233355&oldid=5859303], [//ku.wiktionary.org/w/index.php?title=s%C3%AAw&diff=6233097&oldid=6233003], [//ku.wiktionary.org/w/index.php?title=sewz&diff=6233313&oldid=6069107], ... Spas! [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 01:16, 2 gulan 2026 (UTC) == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 gulan 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|gotûbêj]])</bdi> 17:12, 23 hezîran 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 hezîran 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Jêbirina ferhenga Sadallah == Merheba @[[Bikarhêner:Guherto|Guherto]] Îmkan heye lîsteyeke wisa çêkî ku hemû sayfeyên Cyrusbot çêkir yên ku tê de tenê tercimeyeke îngilîzî heye û ev tercime jî hatibe jêbirin? Nimûne ''[[derdzanî]], [[êşzanî]]'' tenê tercimeya [[pestology]] heye ew jî ji ber heqê telîfê hatiye jêbirin. Nimûneyeke din ''zêrrgeh'', ''zêrrkar'' [[goldsmith]] hatiye jêbirin zêr wekî zêrr hatiye guhartin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:48, 26 hezîran 2026 (UTC) == Beşa Tewandin bo kurmancî == Bi ya min şablona {{ş|ku-tewîn-nav}} û ya fiîlê em bixin beşa Tewandinê (wekî [[şodir|zazakî]]. Bi vî awayî hem ji aliyê şiklî ve hem jî ji aliyê bikaranînê ve xweştir xuya bike. Eger di qismê Tewandinê de be, ê ku dixwaze îzah û notên xwe yan jî emilandinên din jî dikare binivîse. Hûn çi dibêjin? @[[Bikarhêner:Ferhengvan|Ferhengvan]], @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:05, 6 tîrmeh 2026 (UTC) :Belkî em dikarin Formata şiweyan wekî ya behdînî jî têxin nav şablonê. Pir caran şiklê tabloya Tercimeyan ji ber dirêjbûna şablona teqînê jî xirab dibe wekî [[astrofizîk]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 6 tîrmeh 2026 (UTC) :Min mijarê te li jorê yê xwe dît, fikirên min jî hene eger baş e. Yê ku te gotiye bi min baş dibe, ji ber ku her rûpel ji vê mîna hev dibe. Em ê rindtir jî ferq li nav devokan binivîsin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:44, 7 tîrmeh 2026 (UTC) ::@[[Bikarhêner:Bikarhêner|Bikarhêner]] fikr? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:44, 15 tîrmeh 2026 (UTC) :::Formata ku te teklîf kirîye jî ne xerab e, baş tê xuyan. Feqet bi min halê berê (mewcûd) baştir e. Ji ber ku ev şablon (ku-tewîn-nav) bi piranî kurt in û ji bo her kesî ne mihîm e, lewma li kinarê bi formeke hebe ku karibe were vekirin û girtin baştir e. Lê belê ger şablon dirêjtir bin, em karin wekî ya wîkîya almanî bikin (ew jî wekî teklîfa te ye). -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 15 tîrmeh 2026 (UTC) == Reşwî == Silav ji we gî re, Pirsekê min heye. Ez difikirim şablonekê din çê bikim boy devokek kurmancî, yê êla Reşwî. Ew lêkerên xwe hinek cuda ditewînin. Mesela te hem "ez dikim" bêjî yan jî "ez dikime", "em dikinî, em tênî, te em kuştinî" (ne "em dikin") dema xwe yek in lê maneyên xwe ne yek in, "ez bikim" "ez ê bikim" "ez bikime" û dewamên xwe hemû demên xwe yek in lê mane dîsa ne yek in. Eger min çê kir, şûna xwe li ku derê tînim? Ez difikirim li tewandina devokên kurdî yê ku "tabên" xwe hene "kurmancîya rojavayî", "kurmancîya standard" hsw. Lê tewandin ewqes cuda ye dixwaze ku wî şablona tewandina kurdî pir were guherîn. Hûn çi dibêjin? (R: Hûn dewên çi?) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:38, 7 tîrmeh 2026 (UTC) :{{silav|Kurdanparez}} Binêre mînaka devoka ''rojhilatî'': [[Modul:ku-tewandin#L-135]] / [[Modul:ku-tewandin#L-138|L138]] / [[Modul:ku-tewandin#L-143|L-143]], .. Di nav modula ''ku-tewandin"-ê de tê çêkirin. [[Gotûbêja modulê:ku-tewandin#Paşgirên lêkeran di kurmanciya rojhilatî de]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:09, 7 tîrmeh 2026 (UTC) ::PS: Dema niha: [[Modul:ku-tewandin#L-128]]; dema borî: [[Modul:ku-tewandin#L-153]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:15, 7 tîrmeh 2026 (UTC) :::Merheba @[[Bikarhêner:Ghybu|Ghybu]], Eger mimkin be tu dikarî yên devokî têxî binmodulekê û bila modul load bike, bi vî awayî belkî çêkirina yên nû û famkirina modulê hêsantir be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:09, 7 tîrmeh 2026 (UTC) :::Lê di devokê reşwî de hem dema niha yê statîk heye (Îng: I do -> Ez dikim) û yê progressîf heye (I am doing -> Eîz (nêr) Ez î (mê) dikime, yan jî Ez î dikime/Ez ê dikime). Reşwî ji yê standardê pirtir bo zayend ferq tîne, hem jî li dema pêşî (Ez ê bikim (Nêr) ez a bikim (Mê)). Dema pêşî jî formên cuda hene (Ezêk bikime (I will be doing it) û ez ê/a bikim (I will do it)) :::Ev di modûlê têhel bê? [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:09, 8 tîrmeh 2026 (UTC) == WF:Xebat == Min sayfeya [[WF:Xebat]] çêkir, xeletiyên ku hûn ferq dikin ji kerema xwe lê zêde bikin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:35, 15 tîrmeh 2026 (UTC) == Modul:quote == @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]], @[[Bikarhêner:Keyomerd|Keyomerd]], @[[Bikarhêner:Ferhengvan|Ferhengvan]] Merheba, ez modula îngilîzî ya jêgirtin û çavkaniyan li gorî şablonên {{ş|jêder}} format dikim û ji bo ku hertişt wekî formata me ya niha be, gelek serê min diêşe. Ez dibêjim bila em dev ji formata niha berdin wekî ya îngilîzî bi kar bînin ji ber ku gelek xisûsiyetên îngilîzî hene ku yekî dikare biemilîne. Hûn ê bibêjin niha ji kû hat bîra tê, min got [[Wîkîferheng:Xebat#MediaWiki:Gadget-start.js|start.js]] nû bikim û min dît otomatîk çavkanî bi riya [[mw:Citoid]]ê bi riya DOI, ISBN û lînk tê çêkirin, min got wiya jî li skrîptê îlawe bikim loma min [[Wîkîferheng:Xebat#Mediawiki:Gadget-citoid-helper.js|Mediawiki:Gadget-citoid-helper.js]] hazir kir lê hin parametreyên Citoidê kêm bûn, min got ka wana rast bikim, min dît formata me ya niha ti standard bi kar nayîne tenê parametreyan bi virgulê li hev dixe. Ez dibêjim formata îngilîzî baştir e, hem ne îtalîk e ku bi hêsanî tên xwendin, hem jî tarîx û çavkanî herî pêşî tên nîşandan ku ji bo peyitandinê bo min muhîm e. Modula îngilîzî de hema bêje her tişt hatiye çêkirin, eger em rûnin tenê yên lazim li şablona çavkaniyên xwe binivîsin ew ê gelek wext bistîne. Eger em modula îngilîzî bi kar bînin, em ê hem karibin şablonên îngilîzî bi hêsanî û rast kopî bikin hem jî kurdîkirina parametreyan gelek hêsan e. Fikir? --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:20, 24 tîrmeh 2026 (UTC) : Ji bo miqayesekirinê bnr. [[:en:Template:quote-book]] / [[Şablon:jêder-kitêb/ceribandin]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:32, 24 tîrmeh 2026 (UTC) ::Bi min bila yê mewcûd jî bimîne, ew jî şiklen xweş û baştir e. Feqet bi min jî yên îngilîzî rehettir in, eger rastkirina yê mewcûd zehmet be, em rasterast wan ji xwe re bînin û tercime bikin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:41, 24 tîrmeh 2026 (UTC) :::Ez êvarê ve dixebitim, min nêzîk kiribû lê min got belkî hûn qane bibin lê xuya ye hûn ê hîn serê min gelek biêşînin {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:59, 24 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Bikarhêner|Bikarhêner]] û @[[Bikarhêner:Ghybu|Ghybu]] Eger îtîrazek tinebe, ez ê îtalîk ji jêgirtinê rakim... Jixwe bi riya [jêgirtin] dikare were veşartin û her daim bi * dest pê dike loma bi hêsanî tê fêmkirin û xwendin rihettir dibe. Bnr. [https://ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:ceribandin/nim%C3%BBne&oldid=6277132#L%C3%AAker_2 ceribandinê] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:13, 24 tîrmeh 2026 (UTC) == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 tîrmeh 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == ''mê'' yan ''nêr'' li gorî maneyê / ''mê'' yan ''nêr'' (bikaranîn dudil e) == [//ku.wiktionary.org/w/index.php?title=xelat&diff=prev&oldid=6291766]: Mixabin pirr bikarhêner şûnda parametreya <code>z=m/n</code> ('' m yan n li gorî maneyê'') <code>z=mn</code> (''m yan n (bikaranîn dudil e)'') bi kar tînin ([[Şablon:navdêr#Parametre]]) ji ber ku di nav her du nivîsê de pir ferq nebînin. Nizanim em ê dîsa parametreya <code>z=nt</code> (''nêtar'') çêkin, wekî berê: [//ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:D%C3%AEwan/ar%C5%9F%C3%AEv_2019&oldid=6104681#Zayend]. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 00:17, 28 tîrmeh 2026 (UTC) p5ulfqh2bo7eco31aga7hwc9niukn9p 6291811 6291768 2026-07-28T05:33:05Z Wikihez 7344 /* mê yan nêr li gorî maneyê / mê yan nêr (bikaranîn dudil e) */ 6291811 wikitext text/x-wiki <noinclude>{{Dîwan/arşîv-ser|2026}}</noinclude> {{clear}} == Daxwazên standardkirinê == https://ku.wiktionary.org/wiki/W%C3%AEk%C3%AEferheng:Daxwaz%C3%AAn_standardkirin%C3%AA, Gelo di vê malperê de peyvên hatîye standart kirin; ji malperê rakin? Zêde tehlîhev e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:03, 8 kanûna paşîn 2026 (UTC) :@[[Bikarhêner:Rewiye tine|Rewiye tine]] [[Taybet:Tercîh#mw-prefsection-gadgets]] li vir amûra [[MediaWiki:Gadget-aWa.js/belgekirin|awa]] aktîv bike û pê re dikarî gotûbêjan arşîv bikî. Li sayfa [[WF:DS]] li kêleka her sernavê gotûbêjê <nowiki>[arşîv bike]</nowiki> derdikeve, pê lê bike û ew ê arşîv bike. Eger nikarî tu tenê şablona {{ş|ds-kirî}} îlawe bike, ez ê dûre arşîv bikim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:35, 5 tîrmeh 2026 (UTC) == Standartkirin == Sala borî, min pêşnîyazek kiribû. Halî hazir piştî daxwaza standarkirinê em du heftî disekinin, eger kesek fikrek dîyar neke. Raste rast peyv li gor ferhenga standart a mezopotamyayê tê standart kirin. Ji xwe sazîyek vê karî dike çima em vê barî dikin stuyê xwe. Mesela ez çaxe di wîkîferhengê de peyvek digêrim; standart a peyvê jî li cem xwe kontrol dikim. Eger destûr hebe bi germî dikarim wê malperê standart bikim. Benda bûna du heftîyan gelo ne zehmet e? Duyemîn pêşnîyaza min nîşandana standarta peyvê di malpera de ye. Kesek dema malperan binêre, divê li jora malperan bibîne ku ev peyv standart e. Ev jî hîzmet e. Çimkî nivîskar, wergêr, edîtor, rojnemavan hez dikin bi peyvê standart binivîsin. https://ku.wiktionary.org/wiki/k%C3%AAf li vir wekî mînak min daye nîşan. Lê îfade eger wisa be: Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r. 253) e yê çetir be. Çimkî îfadeya berê de peyva kurdî-tirkî derbas dibe û di mejîyê mirov de tevlihevî çêdibe.@[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:25, 8 kanûna paşîn 2026 (UTC) :Merheba. Hevalno dîyar e karê standarkirinê li wîkîferhengê rawestîya ye. Min sê peyv ji bo standartkirinê qeyd kir. Kes li ser şîrove nenivîsî. Mehek jî li ser derbas bû. Aniha ez dikarim van rupelan biguherim. Li gor qaîdeya hatine danîn wisa ye. Daxwaza min heta niha jî ew e kelîmeyên di ferhenga standartkirinê de heyî divê em bikaribin rasterast li vir jî bikin standart. An jî demê kurttir bikin. Li weqfa mezapotamyayê 20 mirov digêhin hev li ser peyvekî seetan nîqaş dikin. Ma hewceyê em jî li vir nîqaş bikin? Tevlî vê jî ji xwe kes li ser vê mijare nasekîne van dema. Xeynî vê pêşnîyaza min nîşandana standarta peyvê di malpera de hebû. Li ser malperê 'Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r.253) e' Tiştek mîna wî hebe yê gelek kêrî her cure nivîskarê me were. Çimkî hin nivîskarên me hez dike bi kelîmeyên standart binivîse. Di malperê de bila vê hêsanî fam bike çêtir e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Ghybu|Ghybu]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 18:35, 17 sibat 2026 (UTC) ::Merheba @[[Bikarhêner:Rewiye tine|Rewiye tine]]. Ev format pir xirab dibe. Tu dikarî li beşa Çavkaniyê binivîsî bi şablona {{ş|kitêb}} binivîsî çêtir e û tê eynî maneyê. Lê her kes standarda Weqfa Mezopotamyayê qebûl nakin û ez jî şibhê dikim ku ev websîte bi awayekî kolektîv tê çêkirin an na. Loma em bi ya kitêba rastnivisînê çêkin û eger îtîraz tinebe, şablona {{ş|ds-kirî}} li gotûbêja [[WF:DS]] binivîse, dûre li gotûbêjê arşîv bike, ne hewce ye li hêviya kesên din bisekinî. Eger itirazek hebe, ê ku dixwaze dûre dîsa şablona ds zêde bike. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:30, 5 tîrmeh 2026 (UTC) :::[https://berwarnews.com/ferhenga-rastnivisine-qonaxeke-giring-a-standardkirina-kurmanci-ye/ Roportaja Mikail Bülbül] li ser proseya standardkirinê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:57, 9 tîrmeh 2026 (UTC) ::::Min nû dît an jî nû hatiye zêdekirin lê meqaleyek bi navê [https://www.ferhengkurdi.com/?q=iltihap&modal=lijne lijneya edîtorîyê] nivîsandine [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:40, 22 tîrmeh 2026 (UTC) == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 kanûna paşîn 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Bikarhêner:MediaWiki message delivery|MediaWiki message delivery]] ([[Gotûbêja bikarhêner:MediaWiki message delivery|gotûbêj]]) 00:58, 26 nîsan 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == Guharto == : <small>→ Ji rûpela ''[//ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAj:berf%C3%AEtik&oldid=6233338 Gotûbêj:berfîtik]'' hatiye girtin.</small> Silav {{r|Ghybu}} ma hewce ye em guhartoyan jî kategorîze bikin? Li vê [[ژیشک]] binere, tije guhartoyên wê hene, ku em ji gişan re guhandar binivîsin dê 10 navên heman hebin di nav wê kategorîyê de. Tu çi difikirî? [[Bikarhêner:Keyomerd|Keyomerd]] ([[Gotûbêja bikarhêner:Keyomerd|gotûbêj]]) 09:40, 26 nîsan 2026 (UTC) :{{silav|Keyomerd}}. Erê, problem çî ye? {{=)}} Ew jî tên bikaranîn... Dema ku peyvek tê çêkirin hewce ye ku em hemû agahiyên wan binivîsin: bilêvkirin, bikaranîn, mînak, terîm, herêm, tewandin, etîmolojî... :Bi min peyvên ku wekî ''guherto'' hatine nivîsandin bi nivîsa {{w|Italic type|îtalîk|ziman=en}} (xwahr) di nav kategoriyan de werin nişan kirin (ji bo cudakirinê). {{ping|Ferhengvan|Bikarhêner}} [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:40, 30 nîsan 2026 (UTC) ::Yên '''''nestandard''''' di kategorîyan de biferq werin nîşandan baştir e. Qene em karibin wan ji yên stadard ferq bikin. @[[Bikarhêner:Ghybu|Ghybu]] Xêra xwe hûn sîstemeke wisa çêkin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:36, 1 gulan 2026 (UTC) :::Merheba @[[Bikarhêner:Keyomerd|Keyomerd]] û @[[Bikarhêner:Bikarhêner|Bikarhêner]] ev xisûsiyet jixwe di şablonên rêzimanê de heye, wextê {{param|formaalt|1}} dinivîsin, made dikeve Kategoriya [[:Kategorî:Formên alternatîv bi kurmancî]] li gorî koda zimanî jî zimanên din tê çêkirin. Hemû madeyên kurmancî bi alfabeya erebî dikevin vê kategoriyê lê nizanim ev tiştekî rast e Yan xelet e, ji bo nîşandanê min çêkiribû lê min hîn wext nedît ku nîqaşek li ser çêkim. Qaîdeyên bikaranîna vê parametreyê di wîkiya îngilîzî de jî tam ne belî ye. Du gotûbêj [https://en.wiktionary.org/wiki/Wiktionary:Requests_for_moves,_mergers_and_splits#Category:Alternative_forms_by_language] [https://en.wiktionary.org/wiki/Wiktionary:Beer_parlour/2024/June#Decluttering_the_altform_mess] çêkirine lê ji bo îngilîzî ev parametre nehatiye bikaranîn. Min ji bo nîşandanê niha [https://ku.wiktionary.org/w/index.php?title=bax%C3%A7%C3%AA_zarokan&diff=prev&oldid=6241372] ceriband lê bi min xelet e. Em çawa bikin? Kengî vê parametreyê bi kar bînin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:29, 8 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Tu çi difikirî? Ji bo zazakî [https://ku.wiktionary.org/w/index.php?title=a_c%C4%B1_geyrayene&oldid=6241396 wisa] bikin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:55, 8 tîrmeh 2026 (UTC) :::::Kategorîyekê cuda baş dibe. Wextê ku ez li kategorîya "lekêren bi zazakî" dinêrim, ez hem formê bi şikilê Johnsonê û formê standardê dibînim. Zaten wexte ku ez dikevim ê Johnsonê, min dibe formê standardê. Kategorîyekê cuda, bi taybetî ji bo nivîsandinên alternatîf, baş dibe. :::::Lê em bîr nekin ku wextê ku em bo formên alternatîf yên devokî qal dikin, belkî adil neye ku em ev bişînin derekê din yê ku însan ewqas nabînin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:03, 8 tîrmeh 2026 (UTC) ::::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Gelo min rast fêm kir? Tu dibêjî formên {{q|ku|kîvroşk}} bi dîqet werin guhartokirin lê bi yên bi alfabeya Jacobsonê hemû bikin {{param|formaalt|1}}? Formên Jacobsonê dê bikevin Kategoriya [[:Kategorî:Lêker bi zazakî|Lêker bi zazakî]] û [[:Kategorî:Lema bi zazakî|Lema bi zazakî]] yan na? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:55, 8 tîrmeh 2026 (UTC) :::::::Bi min naxwaze di wan kategoriyan de bikeve. Wek tu dibînî dûplîkat pir hene. Bi min çareya baştir yên Johnsonê di katehgorîyekê din bikevin (bila format li rûpelan neyin guherandin, bi tenê kategorî) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 00:37, 9 tîrmeh 2026 (UTC) == Peyvên soranî bi latînî ([[:Kategorî:Soranî]]) == Silav, di nav vê kategoriyê (''[[:Kategorî:Soranî]]'') de pirr peyv tenê bi alfabeya latînî hatine nivîsandin. Divê ew mutleq jî bi alfabeya erebî werin transkrîbe kirin ji ber ku soranî bi alfabeya erebî tê nivîsand... Bikarênerên ku soranî dizanin dikarin wan sererast bikin? Mînakên guhertinan: [//ku.wiktionary.org/w/index.php?title=zor%C3%AEne&curid=6584&diff=6233355&oldid=5859303], [//ku.wiktionary.org/w/index.php?title=s%C3%AAw&diff=6233097&oldid=6233003], [//ku.wiktionary.org/w/index.php?title=sewz&diff=6233313&oldid=6069107], ... Spas! [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 01:16, 2 gulan 2026 (UTC) == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 gulan 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|gotûbêj]])</bdi> 17:12, 23 hezîran 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 hezîran 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Jêbirina ferhenga Sadallah == Merheba @[[Bikarhêner:Guherto|Guherto]] Îmkan heye lîsteyeke wisa çêkî ku hemû sayfeyên Cyrusbot çêkir yên ku tê de tenê tercimeyeke îngilîzî heye û ev tercime jî hatibe jêbirin? Nimûne ''[[derdzanî]], [[êşzanî]]'' tenê tercimeya [[pestology]] heye ew jî ji ber heqê telîfê hatiye jêbirin. Nimûneyeke din ''zêrrgeh'', ''zêrrkar'' [[goldsmith]] hatiye jêbirin zêr wekî zêrr hatiye guhartin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:48, 26 hezîran 2026 (UTC) == Beşa Tewandin bo kurmancî == Bi ya min şablona {{ş|ku-tewîn-nav}} û ya fiîlê em bixin beşa Tewandinê (wekî [[şodir|zazakî]]. Bi vî awayî hem ji aliyê şiklî ve hem jî ji aliyê bikaranînê ve xweştir xuya bike. Eger di qismê Tewandinê de be, ê ku dixwaze îzah û notên xwe yan jî emilandinên din jî dikare binivîse. Hûn çi dibêjin? @[[Bikarhêner:Ferhengvan|Ferhengvan]], @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:05, 6 tîrmeh 2026 (UTC) :Belkî em dikarin Formata şiweyan wekî ya behdînî jî têxin nav şablonê. Pir caran şiklê tabloya Tercimeyan ji ber dirêjbûna şablona teqînê jî xirab dibe wekî [[astrofizîk]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 6 tîrmeh 2026 (UTC) :Min mijarê te li jorê yê xwe dît, fikirên min jî hene eger baş e. Yê ku te gotiye bi min baş dibe, ji ber ku her rûpel ji vê mîna hev dibe. Em ê rindtir jî ferq li nav devokan binivîsin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:44, 7 tîrmeh 2026 (UTC) ::@[[Bikarhêner:Bikarhêner|Bikarhêner]] fikr? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:44, 15 tîrmeh 2026 (UTC) :::Formata ku te teklîf kirîye jî ne xerab e, baş tê xuyan. Feqet bi min halê berê (mewcûd) baştir e. Ji ber ku ev şablon (ku-tewîn-nav) bi piranî kurt in û ji bo her kesî ne mihîm e, lewma li kinarê bi formeke hebe ku karibe were vekirin û girtin baştir e. Lê belê ger şablon dirêjtir bin, em karin wekî ya wîkîya almanî bikin (ew jî wekî teklîfa te ye). -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 15 tîrmeh 2026 (UTC) == Reşwî == Silav ji we gî re, Pirsekê min heye. Ez difikirim şablonekê din çê bikim boy devokek kurmancî, yê êla Reşwî. Ew lêkerên xwe hinek cuda ditewînin. Mesela te hem "ez dikim" bêjî yan jî "ez dikime", "em dikinî, em tênî, te em kuştinî" (ne "em dikin") dema xwe yek in lê maneyên xwe ne yek in, "ez bikim" "ez ê bikim" "ez bikime" û dewamên xwe hemû demên xwe yek in lê mane dîsa ne yek in. Eger min çê kir, şûna xwe li ku derê tînim? Ez difikirim li tewandina devokên kurdî yê ku "tabên" xwe hene "kurmancîya rojavayî", "kurmancîya standard" hsw. Lê tewandin ewqes cuda ye dixwaze ku wî şablona tewandina kurdî pir were guherîn. Hûn çi dibêjin? (R: Hûn dewên çi?) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:38, 7 tîrmeh 2026 (UTC) :{{silav|Kurdanparez}} Binêre mînaka devoka ''rojhilatî'': [[Modul:ku-tewandin#L-135]] / [[Modul:ku-tewandin#L-138|L138]] / [[Modul:ku-tewandin#L-143|L-143]], .. Di nav modula ''ku-tewandin"-ê de tê çêkirin. [[Gotûbêja modulê:ku-tewandin#Paşgirên lêkeran di kurmanciya rojhilatî de]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:09, 7 tîrmeh 2026 (UTC) ::PS: Dema niha: [[Modul:ku-tewandin#L-128]]; dema borî: [[Modul:ku-tewandin#L-153]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:15, 7 tîrmeh 2026 (UTC) :::Merheba @[[Bikarhêner:Ghybu|Ghybu]], Eger mimkin be tu dikarî yên devokî têxî binmodulekê û bila modul load bike, bi vî awayî belkî çêkirina yên nû û famkirina modulê hêsantir be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:09, 7 tîrmeh 2026 (UTC) :::Lê di devokê reşwî de hem dema niha yê statîk heye (Îng: I do -> Ez dikim) û yê progressîf heye (I am doing -> Eîz (nêr) Ez î (mê) dikime, yan jî Ez î dikime/Ez ê dikime). Reşwî ji yê standardê pirtir bo zayend ferq tîne, hem jî li dema pêşî (Ez ê bikim (Nêr) ez a bikim (Mê)). Dema pêşî jî formên cuda hene (Ezêk bikime (I will be doing it) û ez ê/a bikim (I will do it)) :::Ev di modûlê têhel bê? [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:09, 8 tîrmeh 2026 (UTC) == WF:Xebat == Min sayfeya [[WF:Xebat]] çêkir, xeletiyên ku hûn ferq dikin ji kerema xwe lê zêde bikin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:35, 15 tîrmeh 2026 (UTC) == Modul:quote == @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]], @[[Bikarhêner:Keyomerd|Keyomerd]], @[[Bikarhêner:Ferhengvan|Ferhengvan]] Merheba, ez modula îngilîzî ya jêgirtin û çavkaniyan li gorî şablonên {{ş|jêder}} format dikim û ji bo ku hertişt wekî formata me ya niha be, gelek serê min diêşe. Ez dibêjim bila em dev ji formata niha berdin wekî ya îngilîzî bi kar bînin ji ber ku gelek xisûsiyetên îngilîzî hene ku yekî dikare biemilîne. Hûn ê bibêjin niha ji kû hat bîra tê, min got [[Wîkîferheng:Xebat#MediaWiki:Gadget-start.js|start.js]] nû bikim û min dît otomatîk çavkanî bi riya [[mw:Citoid]]ê bi riya DOI, ISBN û lînk tê çêkirin, min got wiya jî li skrîptê îlawe bikim loma min [[Wîkîferheng:Xebat#Mediawiki:Gadget-citoid-helper.js|Mediawiki:Gadget-citoid-helper.js]] hazir kir lê hin parametreyên Citoidê kêm bûn, min got ka wana rast bikim, min dît formata me ya niha ti standard bi kar nayîne tenê parametreyan bi virgulê li hev dixe. Ez dibêjim formata îngilîzî baştir e, hem ne îtalîk e ku bi hêsanî tên xwendin, hem jî tarîx û çavkanî herî pêşî tên nîşandan ku ji bo peyitandinê bo min muhîm e. Modula îngilîzî de hema bêje her tişt hatiye çêkirin, eger em rûnin tenê yên lazim li şablona çavkaniyên xwe binivîsin ew ê gelek wext bistîne. Eger em modula îngilîzî bi kar bînin, em ê hem karibin şablonên îngilîzî bi hêsanî û rast kopî bikin hem jî kurdîkirina parametreyan gelek hêsan e. Fikir? --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:20, 24 tîrmeh 2026 (UTC) : Ji bo miqayesekirinê bnr. [[:en:Template:quote-book]] / [[Şablon:jêder-kitêb/ceribandin]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:32, 24 tîrmeh 2026 (UTC) ::Bi min bila yê mewcûd jî bimîne, ew jî şiklen xweş û baştir e. Feqet bi min jî yên îngilîzî rehettir in, eger rastkirina yê mewcûd zehmet be, em rasterast wan ji xwe re bînin û tercime bikin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:41, 24 tîrmeh 2026 (UTC) :::Ez êvarê ve dixebitim, min nêzîk kiribû lê min got belkî hûn qane bibin lê xuya ye hûn ê hîn serê min gelek biêşînin {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:59, 24 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Bikarhêner|Bikarhêner]] û @[[Bikarhêner:Ghybu|Ghybu]] Eger îtîrazek tinebe, ez ê îtalîk ji jêgirtinê rakim... Jixwe bi riya [jêgirtin] dikare were veşartin û her daim bi * dest pê dike loma bi hêsanî tê fêmkirin û xwendin rihettir dibe. Bnr. [https://ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:ceribandin/nim%C3%BBne&oldid=6277132#L%C3%AAker_2 ceribandinê] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:13, 24 tîrmeh 2026 (UTC) == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 tîrmeh 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == ''mê'' yan ''nêr'' li gorî maneyê / ''mê'' yan ''nêr'' (bikaranîn dudil e) == [//ku.wiktionary.org/w/index.php?title=xelat&diff=prev&oldid=6291766]: Mixabin pirr bikarhêner şûnda parametreya <code>z=m/n</code> ('' m yan n li gorî maneyê'') <code>z=mn</code> (''m yan n (bikaranîn dudil e)'') bi kar tînin ([[Şablon:navdêr#Parametre]]) ji ber ku di nav her du nivîsê de pir ferq nebînin. Nizanim em ê dîsa parametreya <code>z=nt</code> (''nêtar'') çêkin, wekî berê: [//ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:D%C3%AEwan/ar%C5%9F%C3%AEv_2019&oldid=6104681#Zayend]. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 00:17, 28 tîrmeh 2026 (UTC) :Merheba {{r|Ghybu}} {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=mn}}</nowiki>}} Ya din jî; {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=m/n}}</nowiki>}} Tu dixwazî em wana berevajî bikin? Not: nêtar ji bo kurmancî nabe, mn û m/n baş in. Berê ji ber ku m/n tinebû, her kes li gorî parametreyên heyî dixebitî. Niha hene bi min problem nîne eger em berevajî nekin.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:32, 28 tîrmeh 2026 (UTC) fqmd3p9ehw4h55v74zwxjammx7qw8x4 6291814 6291811 2026-07-28T05:49:57Z Wikihez 7344 /* mê yan nêr li gorî maneyê / mê yan nêr (bikaranîn dudil e) */ 6291814 wikitext text/x-wiki <noinclude>{{Dîwan/arşîv-ser|2026}}</noinclude> {{clear}} == Daxwazên standardkirinê == https://ku.wiktionary.org/wiki/W%C3%AEk%C3%AEferheng:Daxwaz%C3%AAn_standardkirin%C3%AA, Gelo di vê malperê de peyvên hatîye standart kirin; ji malperê rakin? Zêde tehlîhev e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:03, 8 kanûna paşîn 2026 (UTC) :@[[Bikarhêner:Rewiye tine|Rewiye tine]] [[Taybet:Tercîh#mw-prefsection-gadgets]] li vir amûra [[MediaWiki:Gadget-aWa.js/belgekirin|awa]] aktîv bike û pê re dikarî gotûbêjan arşîv bikî. Li sayfa [[WF:DS]] li kêleka her sernavê gotûbêjê <nowiki>[arşîv bike]</nowiki> derdikeve, pê lê bike û ew ê arşîv bike. Eger nikarî tu tenê şablona {{ş|ds-kirî}} îlawe bike, ez ê dûre arşîv bikim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:35, 5 tîrmeh 2026 (UTC) == Standartkirin == Sala borî, min pêşnîyazek kiribû. Halî hazir piştî daxwaza standarkirinê em du heftî disekinin, eger kesek fikrek dîyar neke. Raste rast peyv li gor ferhenga standart a mezopotamyayê tê standart kirin. Ji xwe sazîyek vê karî dike çima em vê barî dikin stuyê xwe. Mesela ez çaxe di wîkîferhengê de peyvek digêrim; standart a peyvê jî li cem xwe kontrol dikim. Eger destûr hebe bi germî dikarim wê malperê standart bikim. Benda bûna du heftîyan gelo ne zehmet e? Duyemîn pêşnîyaza min nîşandana standarta peyvê di malpera de ye. Kesek dema malperan binêre, divê li jora malperan bibîne ku ev peyv standart e. Ev jî hîzmet e. Çimkî nivîskar, wergêr, edîtor, rojnemavan hez dikin bi peyvê standart binivîsin. https://ku.wiktionary.org/wiki/k%C3%AAf li vir wekî mînak min daye nîşan. Lê îfade eger wisa be: Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r. 253) e yê çetir be. Çimkî îfadeya berê de peyva kurdî-tirkî derbas dibe û di mejîyê mirov de tevlihevî çêdibe.@[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:25, 8 kanûna paşîn 2026 (UTC) :Merheba. Hevalno dîyar e karê standarkirinê li wîkîferhengê rawestîya ye. Min sê peyv ji bo standartkirinê qeyd kir. Kes li ser şîrove nenivîsî. Mehek jî li ser derbas bû. Aniha ez dikarim van rupelan biguherim. Li gor qaîdeya hatine danîn wisa ye. Daxwaza min heta niha jî ew e kelîmeyên di ferhenga standartkirinê de heyî divê em bikaribin rasterast li vir jî bikin standart. An jî demê kurttir bikin. Li weqfa mezapotamyayê 20 mirov digêhin hev li ser peyvekî seetan nîqaş dikin. Ma hewceyê em jî li vir nîqaş bikin? Tevlî vê jî ji xwe kes li ser vê mijare nasekîne van dema. Xeynî vê pêşnîyaza min nîşandana standarta peyvê di malpera de hebû. Li ser malperê 'Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r.253) e' Tiştek mîna wî hebe yê gelek kêrî her cure nivîskarê me were. Çimkî hin nivîskarên me hez dike bi kelîmeyên standart binivîse. Di malperê de bila vê hêsanî fam bike çêtir e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Ghybu|Ghybu]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 18:35, 17 sibat 2026 (UTC) ::Merheba @[[Bikarhêner:Rewiye tine|Rewiye tine]]. Ev format pir xirab dibe. Tu dikarî li beşa Çavkaniyê binivîsî bi şablona {{ş|kitêb}} binivîsî çêtir e û tê eynî maneyê. Lê her kes standarda Weqfa Mezopotamyayê qebûl nakin û ez jî şibhê dikim ku ev websîte bi awayekî kolektîv tê çêkirin an na. Loma em bi ya kitêba rastnivisînê çêkin û eger îtîraz tinebe, şablona {{ş|ds-kirî}} li gotûbêja [[WF:DS]] binivîse, dûre li gotûbêjê arşîv bike, ne hewce ye li hêviya kesên din bisekinî. Eger itirazek hebe, ê ku dixwaze dûre dîsa şablona ds zêde bike. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:30, 5 tîrmeh 2026 (UTC) :::[https://berwarnews.com/ferhenga-rastnivisine-qonaxeke-giring-a-standardkirina-kurmanci-ye/ Roportaja Mikail Bülbül] li ser proseya standardkirinê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:57, 9 tîrmeh 2026 (UTC) ::::Min nû dît an jî nû hatiye zêdekirin lê meqaleyek bi navê [https://www.ferhengkurdi.com/?q=iltihap&modal=lijne lijneya edîtorîyê] nivîsandine [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:40, 22 tîrmeh 2026 (UTC) == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 kanûna paşîn 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Bikarhêner:MediaWiki message delivery|MediaWiki message delivery]] ([[Gotûbêja bikarhêner:MediaWiki message delivery|gotûbêj]]) 00:58, 26 nîsan 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == Guharto == : <small>→ Ji rûpela ''[//ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAj:berf%C3%AEtik&oldid=6233338 Gotûbêj:berfîtik]'' hatiye girtin.</small> Silav {{r|Ghybu}} ma hewce ye em guhartoyan jî kategorîze bikin? Li vê [[ژیشک]] binere, tije guhartoyên wê hene, ku em ji gişan re guhandar binivîsin dê 10 navên heman hebin di nav wê kategorîyê de. Tu çi difikirî? [[Bikarhêner:Keyomerd|Keyomerd]] ([[Gotûbêja bikarhêner:Keyomerd|gotûbêj]]) 09:40, 26 nîsan 2026 (UTC) :{{silav|Keyomerd}}. Erê, problem çî ye? {{=)}} Ew jî tên bikaranîn... Dema ku peyvek tê çêkirin hewce ye ku em hemû agahiyên wan binivîsin: bilêvkirin, bikaranîn, mînak, terîm, herêm, tewandin, etîmolojî... :Bi min peyvên ku wekî ''guherto'' hatine nivîsandin bi nivîsa {{w|Italic type|îtalîk|ziman=en}} (xwahr) di nav kategoriyan de werin nişan kirin (ji bo cudakirinê). {{ping|Ferhengvan|Bikarhêner}} [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:40, 30 nîsan 2026 (UTC) ::Yên '''''nestandard''''' di kategorîyan de biferq werin nîşandan baştir e. Qene em karibin wan ji yên stadard ferq bikin. @[[Bikarhêner:Ghybu|Ghybu]] Xêra xwe hûn sîstemeke wisa çêkin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:36, 1 gulan 2026 (UTC) :::Merheba @[[Bikarhêner:Keyomerd|Keyomerd]] û @[[Bikarhêner:Bikarhêner|Bikarhêner]] ev xisûsiyet jixwe di şablonên rêzimanê de heye, wextê {{param|formaalt|1}} dinivîsin, made dikeve Kategoriya [[:Kategorî:Formên alternatîv bi kurmancî]] li gorî koda zimanî jî zimanên din tê çêkirin. Hemû madeyên kurmancî bi alfabeya erebî dikevin vê kategoriyê lê nizanim ev tiştekî rast e Yan xelet e, ji bo nîşandanê min çêkiribû lê min hîn wext nedît ku nîqaşek li ser çêkim. Qaîdeyên bikaranîna vê parametreyê di wîkiya îngilîzî de jî tam ne belî ye. Du gotûbêj [https://en.wiktionary.org/wiki/Wiktionary:Requests_for_moves,_mergers_and_splits#Category:Alternative_forms_by_language] [https://en.wiktionary.org/wiki/Wiktionary:Beer_parlour/2024/June#Decluttering_the_altform_mess] çêkirine lê ji bo îngilîzî ev parametre nehatiye bikaranîn. Min ji bo nîşandanê niha [https://ku.wiktionary.org/w/index.php?title=bax%C3%A7%C3%AA_zarokan&diff=prev&oldid=6241372] ceriband lê bi min xelet e. Em çawa bikin? Kengî vê parametreyê bi kar bînin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:29, 8 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Tu çi difikirî? Ji bo zazakî [https://ku.wiktionary.org/w/index.php?title=a_c%C4%B1_geyrayene&oldid=6241396 wisa] bikin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:55, 8 tîrmeh 2026 (UTC) :::::Kategorîyekê cuda baş dibe. Wextê ku ez li kategorîya "lekêren bi zazakî" dinêrim, ez hem formê bi şikilê Johnsonê û formê standardê dibînim. Zaten wexte ku ez dikevim ê Johnsonê, min dibe formê standardê. Kategorîyekê cuda, bi taybetî ji bo nivîsandinên alternatîf, baş dibe. :::::Lê em bîr nekin ku wextê ku em bo formên alternatîf yên devokî qal dikin, belkî adil neye ku em ev bişînin derekê din yê ku însan ewqas nabînin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:03, 8 tîrmeh 2026 (UTC) ::::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Gelo min rast fêm kir? Tu dibêjî formên {{q|ku|kîvroşk}} bi dîqet werin guhartokirin lê bi yên bi alfabeya Jacobsonê hemû bikin {{param|formaalt|1}}? Formên Jacobsonê dê bikevin Kategoriya [[:Kategorî:Lêker bi zazakî|Lêker bi zazakî]] û [[:Kategorî:Lema bi zazakî|Lema bi zazakî]] yan na? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:55, 8 tîrmeh 2026 (UTC) :::::::Bi min naxwaze di wan kategoriyan de bikeve. Wek tu dibînî dûplîkat pir hene. Bi min çareya baştir yên Johnsonê di katehgorîyekê din bikevin (bila format li rûpelan neyin guherandin, bi tenê kategorî) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 00:37, 9 tîrmeh 2026 (UTC) == Peyvên soranî bi latînî ([[:Kategorî:Soranî]]) == Silav, di nav vê kategoriyê (''[[:Kategorî:Soranî]]'') de pirr peyv tenê bi alfabeya latînî hatine nivîsandin. Divê ew mutleq jî bi alfabeya erebî werin transkrîbe kirin ji ber ku soranî bi alfabeya erebî tê nivîsand... Bikarênerên ku soranî dizanin dikarin wan sererast bikin? Mînakên guhertinan: [//ku.wiktionary.org/w/index.php?title=zor%C3%AEne&curid=6584&diff=6233355&oldid=5859303], [//ku.wiktionary.org/w/index.php?title=s%C3%AAw&diff=6233097&oldid=6233003], [//ku.wiktionary.org/w/index.php?title=sewz&diff=6233313&oldid=6069107], ... Spas! [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 01:16, 2 gulan 2026 (UTC) == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 gulan 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|gotûbêj]])</bdi> 17:12, 23 hezîran 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 hezîran 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Jêbirina ferhenga Sadallah == Merheba @[[Bikarhêner:Guherto|Guherto]] Îmkan heye lîsteyeke wisa çêkî ku hemû sayfeyên Cyrusbot çêkir yên ku tê de tenê tercimeyeke îngilîzî heye û ev tercime jî hatibe jêbirin? Nimûne ''[[derdzanî]], [[êşzanî]]'' tenê tercimeya [[pestology]] heye ew jî ji ber heqê telîfê hatiye jêbirin. Nimûneyeke din ''zêrrgeh'', ''zêrrkar'' [[goldsmith]] hatiye jêbirin zêr wekî zêrr hatiye guhartin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:48, 26 hezîran 2026 (UTC) == Beşa Tewandin bo kurmancî == Bi ya min şablona {{ş|ku-tewîn-nav}} û ya fiîlê em bixin beşa Tewandinê (wekî [[şodir|zazakî]]. Bi vî awayî hem ji aliyê şiklî ve hem jî ji aliyê bikaranînê ve xweştir xuya bike. Eger di qismê Tewandinê de be, ê ku dixwaze îzah û notên xwe yan jî emilandinên din jî dikare binivîse. Hûn çi dibêjin? @[[Bikarhêner:Ferhengvan|Ferhengvan]], @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:05, 6 tîrmeh 2026 (UTC) :Belkî em dikarin Formata şiweyan wekî ya behdînî jî têxin nav şablonê. Pir caran şiklê tabloya Tercimeyan ji ber dirêjbûna şablona teqînê jî xirab dibe wekî [[astrofizîk]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 6 tîrmeh 2026 (UTC) :Min mijarê te li jorê yê xwe dît, fikirên min jî hene eger baş e. Yê ku te gotiye bi min baş dibe, ji ber ku her rûpel ji vê mîna hev dibe. Em ê rindtir jî ferq li nav devokan binivîsin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:44, 7 tîrmeh 2026 (UTC) ::@[[Bikarhêner:Bikarhêner|Bikarhêner]] fikr? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:44, 15 tîrmeh 2026 (UTC) :::Formata ku te teklîf kirîye jî ne xerab e, baş tê xuyan. Feqet bi min halê berê (mewcûd) baştir e. Ji ber ku ev şablon (ku-tewîn-nav) bi piranî kurt in û ji bo her kesî ne mihîm e, lewma li kinarê bi formeke hebe ku karibe were vekirin û girtin baştir e. Lê belê ger şablon dirêjtir bin, em karin wekî ya wîkîya almanî bikin (ew jî wekî teklîfa te ye). -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 15 tîrmeh 2026 (UTC) == Reşwî == Silav ji we gî re, Pirsekê min heye. Ez difikirim şablonekê din çê bikim boy devokek kurmancî, yê êla Reşwî. Ew lêkerên xwe hinek cuda ditewînin. Mesela te hem "ez dikim" bêjî yan jî "ez dikime", "em dikinî, em tênî, te em kuştinî" (ne "em dikin") dema xwe yek in lê maneyên xwe ne yek in, "ez bikim" "ez ê bikim" "ez bikime" û dewamên xwe hemû demên xwe yek in lê mane dîsa ne yek in. Eger min çê kir, şûna xwe li ku derê tînim? Ez difikirim li tewandina devokên kurdî yê ku "tabên" xwe hene "kurmancîya rojavayî", "kurmancîya standard" hsw. Lê tewandin ewqes cuda ye dixwaze ku wî şablona tewandina kurdî pir were guherîn. Hûn çi dibêjin? (R: Hûn dewên çi?) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:38, 7 tîrmeh 2026 (UTC) :{{silav|Kurdanparez}} Binêre mînaka devoka ''rojhilatî'': [[Modul:ku-tewandin#L-135]] / [[Modul:ku-tewandin#L-138|L138]] / [[Modul:ku-tewandin#L-143|L-143]], .. Di nav modula ''ku-tewandin"-ê de tê çêkirin. [[Gotûbêja modulê:ku-tewandin#Paşgirên lêkeran di kurmanciya rojhilatî de]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:09, 7 tîrmeh 2026 (UTC) ::PS: Dema niha: [[Modul:ku-tewandin#L-128]]; dema borî: [[Modul:ku-tewandin#L-153]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:15, 7 tîrmeh 2026 (UTC) :::Merheba @[[Bikarhêner:Ghybu|Ghybu]], Eger mimkin be tu dikarî yên devokî têxî binmodulekê û bila modul load bike, bi vî awayî belkî çêkirina yên nû û famkirina modulê hêsantir be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:09, 7 tîrmeh 2026 (UTC) :::Lê di devokê reşwî de hem dema niha yê statîk heye (Îng: I do -> Ez dikim) û yê progressîf heye (I am doing -> Eîz (nêr) Ez î (mê) dikime, yan jî Ez î dikime/Ez ê dikime). Reşwî ji yê standardê pirtir bo zayend ferq tîne, hem jî li dema pêşî (Ez ê bikim (Nêr) ez a bikim (Mê)). Dema pêşî jî formên cuda hene (Ezêk bikime (I will be doing it) û ez ê/a bikim (I will do it)) :::Ev di modûlê têhel bê? [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:09, 8 tîrmeh 2026 (UTC) == WF:Xebat == Min sayfeya [[WF:Xebat]] çêkir, xeletiyên ku hûn ferq dikin ji kerema xwe lê zêde bikin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:35, 15 tîrmeh 2026 (UTC) == Modul:quote == @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]], @[[Bikarhêner:Keyomerd|Keyomerd]], @[[Bikarhêner:Ferhengvan|Ferhengvan]] Merheba, ez modula îngilîzî ya jêgirtin û çavkaniyan li gorî şablonên {{ş|jêder}} format dikim û ji bo ku hertişt wekî formata me ya niha be, gelek serê min diêşe. Ez dibêjim bila em dev ji formata niha berdin wekî ya îngilîzî bi kar bînin ji ber ku gelek xisûsiyetên îngilîzî hene ku yekî dikare biemilîne. Hûn ê bibêjin niha ji kû hat bîra tê, min got [[Wîkîferheng:Xebat#MediaWiki:Gadget-start.js|start.js]] nû bikim û min dît otomatîk çavkanî bi riya [[mw:Citoid]]ê bi riya DOI, ISBN û lînk tê çêkirin, min got wiya jî li skrîptê îlawe bikim loma min [[Wîkîferheng:Xebat#Mediawiki:Gadget-citoid-helper.js|Mediawiki:Gadget-citoid-helper.js]] hazir kir lê hin parametreyên Citoidê kêm bûn, min got ka wana rast bikim, min dît formata me ya niha ti standard bi kar nayîne tenê parametreyan bi virgulê li hev dixe. Ez dibêjim formata îngilîzî baştir e, hem ne îtalîk e ku bi hêsanî tên xwendin, hem jî tarîx û çavkanî herî pêşî tên nîşandan ku ji bo peyitandinê bo min muhîm e. Modula îngilîzî de hema bêje her tişt hatiye çêkirin, eger em rûnin tenê yên lazim li şablona çavkaniyên xwe binivîsin ew ê gelek wext bistîne. Eger em modula îngilîzî bi kar bînin, em ê hem karibin şablonên îngilîzî bi hêsanî û rast kopî bikin hem jî kurdîkirina parametreyan gelek hêsan e. Fikir? --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:20, 24 tîrmeh 2026 (UTC) : Ji bo miqayesekirinê bnr. [[:en:Template:quote-book]] / [[Şablon:jêder-kitêb/ceribandin]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:32, 24 tîrmeh 2026 (UTC) ::Bi min bila yê mewcûd jî bimîne, ew jî şiklen xweş û baştir e. Feqet bi min jî yên îngilîzî rehettir in, eger rastkirina yê mewcûd zehmet be, em rasterast wan ji xwe re bînin û tercime bikin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:41, 24 tîrmeh 2026 (UTC) :::Ez êvarê ve dixebitim, min nêzîk kiribû lê min got belkî hûn qane bibin lê xuya ye hûn ê hîn serê min gelek biêşînin {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:59, 24 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Bikarhêner|Bikarhêner]] û @[[Bikarhêner:Ghybu|Ghybu]] Eger îtîrazek tinebe, ez ê îtalîk ji jêgirtinê rakim... Jixwe bi riya [jêgirtin] dikare were veşartin û her daim bi * dest pê dike loma bi hêsanî tê fêmkirin û xwendin rihettir dibe. Bnr. [https://ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:ceribandin/nim%C3%BBne&oldid=6277132#L%C3%AAker_2 ceribandinê] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:13, 24 tîrmeh 2026 (UTC) == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 tîrmeh 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == ''mê'' yan ''nêr'' li gorî maneyê / ''mê'' yan ''nêr'' (bikaranîn dudil e) == [//ku.wiktionary.org/w/index.php?title=xelat&diff=prev&oldid=6291766]: Mixabin pirr bikarhêner şûnda parametreya <code>z=m/n</code> ('' m yan n li gorî maneyê'') <code>z=mn</code> (''m yan n (bikaranîn dudil e)'') bi kar tînin ([[Şablon:navdêr#Parametre]]) ji ber ku di nav her du nivîsê de pir ferq nebînin. Nizanim em ê dîsa parametreya <code>z=nt</code> (''nêtar'') çêkin, wekî berê: [//ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:D%C3%AEwan/ar%C5%9F%C3%AEv_2019&oldid=6104681#Zayend]. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 00:17, 28 tîrmeh 2026 (UTC) :Merheba {{r|Ghybu}} {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=mn}}</nowiki>}} Ya din jî; {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=m/n}}</nowiki>}} Tu dixwazî em wana berevajî bikin? Not: nêtar ji bo kurmancî nabe, mn û m/n baş in. Berê ji ber ku m/n tinebû, her kes li gorî parametreyên heyî dixebitî. Niha hene bi min problem nîne eger em berevajî nekin.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:32, 28 tîrmeh 2026 (UTC) : Bi min ev format baştir e: {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c1=m|c1etîk=Mêrdîn|c2=n|c2etîk=Dihok}}</nowiki>}} Yan jî: {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|zayend|c1=n|c2=n|c1ref={{Jêgirtin/Celadet Alî Bedirxan/HAWAR Cild 1 Hejmar 1-23 (1932-1933)/1998|hejmar=4|sal=1938}}|c2ref={{Zana Farqînî}}}}</nowiki>}} {{çavkanî}} :--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:49, 28 tîrmeh 2026 (UTC) sbss3nf1z3zz8ogqm2ndka1ne1zmnu3 6291815 6291814 2026-07-28T05:50:27Z Wikihez 7344 6291815 wikitext text/x-wiki <noinclude>{{Dîwan/arşîv-ser|2026}}</noinclude> {{clear}} == Daxwazên standardkirinê == https://ku.wiktionary.org/wiki/W%C3%AEk%C3%AEferheng:Daxwaz%C3%AAn_standardkirin%C3%AA, Gelo di vê malperê de peyvên hatîye standart kirin; ji malperê rakin? Zêde tehlîhev e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:03, 8 kanûna paşîn 2026 (UTC) :@[[Bikarhêner:Rewiye tine|Rewiye tine]] [[Taybet:Tercîh#mw-prefsection-gadgets]] li vir amûra [[MediaWiki:Gadget-aWa.js/belgekirin|awa]] aktîv bike û pê re dikarî gotûbêjan arşîv bikî. Li sayfa [[WF:DS]] li kêleka her sernavê gotûbêjê <nowiki>[arşîv bike]</nowiki> derdikeve, pê lê bike û ew ê arşîv bike. Eger nikarî tu tenê şablona {{ş|ds-kirî}} îlawe bike, ez ê dûre arşîv bikim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:35, 5 tîrmeh 2026 (UTC) == Standartkirin == Sala borî, min pêşnîyazek kiribû. Halî hazir piştî daxwaza standarkirinê em du heftî disekinin, eger kesek fikrek dîyar neke. Raste rast peyv li gor ferhenga standart a mezopotamyayê tê standart kirin. Ji xwe sazîyek vê karî dike çima em vê barî dikin stuyê xwe. Mesela ez çaxe di wîkîferhengê de peyvek digêrim; standart a peyvê jî li cem xwe kontrol dikim. Eger destûr hebe bi germî dikarim wê malperê standart bikim. Benda bûna du heftîyan gelo ne zehmet e? Duyemîn pêşnîyaza min nîşandana standarta peyvê di malpera de ye. Kesek dema malperan binêre, divê li jora malperan bibîne ku ev peyv standart e. Ev jî hîzmet e. Çimkî nivîskar, wergêr, edîtor, rojnemavan hez dikin bi peyvê standart binivîsin. https://ku.wiktionary.org/wiki/k%C3%AAf li vir wekî mînak min daye nîşan. Lê îfade eger wisa be: Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r. 253) e yê çetir be. Çimkî îfadeya berê de peyva kurdî-tirkî derbas dibe û di mejîyê mirov de tevlihevî çêdibe.@[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:25, 8 kanûna paşîn 2026 (UTC) :Merheba. Hevalno dîyar e karê standarkirinê li wîkîferhengê rawestîya ye. Min sê peyv ji bo standartkirinê qeyd kir. Kes li ser şîrove nenivîsî. Mehek jî li ser derbas bû. Aniha ez dikarim van rupelan biguherim. Li gor qaîdeya hatine danîn wisa ye. Daxwaza min heta niha jî ew e kelîmeyên di ferhenga standartkirinê de heyî divê em bikaribin rasterast li vir jî bikin standart. An jî demê kurttir bikin. Li weqfa mezapotamyayê 20 mirov digêhin hev li ser peyvekî seetan nîqaş dikin. Ma hewceyê em jî li vir nîqaş bikin? Tevlî vê jî ji xwe kes li ser vê mijare nasekîne van dema. Xeynî vê pêşnîyaza min nîşandana standarta peyvê di malpera de hebû. Li ser malperê 'Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r.253) e' Tiştek mîna wî hebe yê gelek kêrî her cure nivîskarê me were. Çimkî hin nivîskarên me hez dike bi kelîmeyên standart binivîse. Di malperê de bila vê hêsanî fam bike çêtir e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Ghybu|Ghybu]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 18:35, 17 sibat 2026 (UTC) ::Merheba @[[Bikarhêner:Rewiye tine|Rewiye tine]]. Ev format pir xirab dibe. Tu dikarî li beşa Çavkaniyê binivîsî bi şablona {{ş|kitêb}} binivîsî çêtir e û tê eynî maneyê. Lê her kes standarda Weqfa Mezopotamyayê qebûl nakin û ez jî şibhê dikim ku ev websîte bi awayekî kolektîv tê çêkirin an na. Loma em bi ya kitêba rastnivisînê çêkin û eger îtîraz tinebe, şablona {{ş|ds-kirî}} li gotûbêja [[WF:DS]] binivîse, dûre li gotûbêjê arşîv bike, ne hewce ye li hêviya kesên din bisekinî. Eger itirazek hebe, ê ku dixwaze dûre dîsa şablona ds zêde bike. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:30, 5 tîrmeh 2026 (UTC) :::[https://berwarnews.com/ferhenga-rastnivisine-qonaxeke-giring-a-standardkirina-kurmanci-ye/ Roportaja Mikail Bülbül] li ser proseya standardkirinê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:57, 9 tîrmeh 2026 (UTC) ::::Min nû dît an jî nû hatiye zêdekirin lê meqaleyek bi navê [https://www.ferhengkurdi.com/?q=iltihap&modal=lijne lijneya edîtorîyê] nivîsandine [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:40, 22 tîrmeh 2026 (UTC) == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 kanûna paşîn 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Bikarhêner:MediaWiki message delivery|MediaWiki message delivery]] ([[Gotûbêja bikarhêner:MediaWiki message delivery|gotûbêj]]) 00:58, 26 nîsan 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == Guharto == : <small>→ Ji rûpela ''[//ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAj:berf%C3%AEtik&oldid=6233338 Gotûbêj:berfîtik]'' hatiye girtin.</small> Silav {{r|Ghybu}} ma hewce ye em guhartoyan jî kategorîze bikin? Li vê [[ژیشک]] binere, tije guhartoyên wê hene, ku em ji gişan re guhandar binivîsin dê 10 navên heman hebin di nav wê kategorîyê de. Tu çi difikirî? [[Bikarhêner:Keyomerd|Keyomerd]] ([[Gotûbêja bikarhêner:Keyomerd|gotûbêj]]) 09:40, 26 nîsan 2026 (UTC) :{{silav|Keyomerd}}. Erê, problem çî ye? {{=)}} Ew jî tên bikaranîn... Dema ku peyvek tê çêkirin hewce ye ku em hemû agahiyên wan binivîsin: bilêvkirin, bikaranîn, mînak, terîm, herêm, tewandin, etîmolojî... :Bi min peyvên ku wekî ''guherto'' hatine nivîsandin bi nivîsa {{w|Italic type|îtalîk|ziman=en}} (xwahr) di nav kategoriyan de werin nişan kirin (ji bo cudakirinê). {{ping|Ferhengvan|Bikarhêner}} [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:40, 30 nîsan 2026 (UTC) ::Yên '''''nestandard''''' di kategorîyan de biferq werin nîşandan baştir e. Qene em karibin wan ji yên stadard ferq bikin. @[[Bikarhêner:Ghybu|Ghybu]] Xêra xwe hûn sîstemeke wisa çêkin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:36, 1 gulan 2026 (UTC) :::Merheba @[[Bikarhêner:Keyomerd|Keyomerd]] û @[[Bikarhêner:Bikarhêner|Bikarhêner]] ev xisûsiyet jixwe di şablonên rêzimanê de heye, wextê {{param|formaalt|1}} dinivîsin, made dikeve Kategoriya [[:Kategorî:Formên alternatîv bi kurmancî]] li gorî koda zimanî jî zimanên din tê çêkirin. Hemû madeyên kurmancî bi alfabeya erebî dikevin vê kategoriyê lê nizanim ev tiştekî rast e Yan xelet e, ji bo nîşandanê min çêkiribû lê min hîn wext nedît ku nîqaşek li ser çêkim. Qaîdeyên bikaranîna vê parametreyê di wîkiya îngilîzî de jî tam ne belî ye. Du gotûbêj [https://en.wiktionary.org/wiki/Wiktionary:Requests_for_moves,_mergers_and_splits#Category:Alternative_forms_by_language] [https://en.wiktionary.org/wiki/Wiktionary:Beer_parlour/2024/June#Decluttering_the_altform_mess] çêkirine lê ji bo îngilîzî ev parametre nehatiye bikaranîn. Min ji bo nîşandanê niha [https://ku.wiktionary.org/w/index.php?title=bax%C3%A7%C3%AA_zarokan&diff=prev&oldid=6241372] ceriband lê bi min xelet e. Em çawa bikin? Kengî vê parametreyê bi kar bînin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:29, 8 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Tu çi difikirî? Ji bo zazakî [https://ku.wiktionary.org/w/index.php?title=a_c%C4%B1_geyrayene&oldid=6241396 wisa] bikin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:55, 8 tîrmeh 2026 (UTC) :::::Kategorîyekê cuda baş dibe. Wextê ku ez li kategorîya "lekêren bi zazakî" dinêrim, ez hem formê bi şikilê Johnsonê û formê standardê dibînim. Zaten wexte ku ez dikevim ê Johnsonê, min dibe formê standardê. Kategorîyekê cuda, bi taybetî ji bo nivîsandinên alternatîf, baş dibe. :::::Lê em bîr nekin ku wextê ku em bo formên alternatîf yên devokî qal dikin, belkî adil neye ku em ev bişînin derekê din yê ku însan ewqas nabînin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:03, 8 tîrmeh 2026 (UTC) ::::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Gelo min rast fêm kir? Tu dibêjî formên {{q|ku|kîvroşk}} bi dîqet werin guhartokirin lê bi yên bi alfabeya Jacobsonê hemû bikin {{param|formaalt|1}}? Formên Jacobsonê dê bikevin Kategoriya [[:Kategorî:Lêker bi zazakî|Lêker bi zazakî]] û [[:Kategorî:Lema bi zazakî|Lema bi zazakî]] yan na? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:55, 8 tîrmeh 2026 (UTC) :::::::Bi min naxwaze di wan kategoriyan de bikeve. Wek tu dibînî dûplîkat pir hene. Bi min çareya baştir yên Johnsonê di katehgorîyekê din bikevin (bila format li rûpelan neyin guherandin, bi tenê kategorî) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 00:37, 9 tîrmeh 2026 (UTC) == Peyvên soranî bi latînî ([[:Kategorî:Soranî]]) == Silav, di nav vê kategoriyê (''[[:Kategorî:Soranî]]'') de pirr peyv tenê bi alfabeya latînî hatine nivîsandin. Divê ew mutleq jî bi alfabeya erebî werin transkrîbe kirin ji ber ku soranî bi alfabeya erebî tê nivîsand... Bikarênerên ku soranî dizanin dikarin wan sererast bikin? Mînakên guhertinan: [//ku.wiktionary.org/w/index.php?title=zor%C3%AEne&curid=6584&diff=6233355&oldid=5859303], [//ku.wiktionary.org/w/index.php?title=s%C3%AAw&diff=6233097&oldid=6233003], [//ku.wiktionary.org/w/index.php?title=sewz&diff=6233313&oldid=6069107], ... Spas! [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 01:16, 2 gulan 2026 (UTC) == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 gulan 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|gotûbêj]])</bdi> 17:12, 23 hezîran 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 hezîran 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Jêbirina ferhenga Sadallah == Merheba @[[Bikarhêner:Guherto|Guherto]] Îmkan heye lîsteyeke wisa çêkî ku hemû sayfeyên Cyrusbot çêkir yên ku tê de tenê tercimeyeke îngilîzî heye û ev tercime jî hatibe jêbirin? Nimûne ''[[derdzanî]], [[êşzanî]]'' tenê tercimeya [[pestology]] heye ew jî ji ber heqê telîfê hatiye jêbirin. Nimûneyeke din ''zêrrgeh'', ''zêrrkar'' [[goldsmith]] hatiye jêbirin zêr wekî zêrr hatiye guhartin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:48, 26 hezîran 2026 (UTC) == Beşa Tewandin bo kurmancî == Bi ya min şablona {{ş|ku-tewîn-nav}} û ya fiîlê em bixin beşa Tewandinê (wekî [[şodir|zazakî]]. Bi vî awayî hem ji aliyê şiklî ve hem jî ji aliyê bikaranînê ve xweştir xuya bike. Eger di qismê Tewandinê de be, ê ku dixwaze îzah û notên xwe yan jî emilandinên din jî dikare binivîse. Hûn çi dibêjin? @[[Bikarhêner:Ferhengvan|Ferhengvan]], @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:05, 6 tîrmeh 2026 (UTC) :Belkî em dikarin Formata şiweyan wekî ya behdînî jî têxin nav şablonê. Pir caran şiklê tabloya Tercimeyan ji ber dirêjbûna şablona teqînê jî xirab dibe wekî [[astrofizîk]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 6 tîrmeh 2026 (UTC) :Min mijarê te li jorê yê xwe dît, fikirên min jî hene eger baş e. Yê ku te gotiye bi min baş dibe, ji ber ku her rûpel ji vê mîna hev dibe. Em ê rindtir jî ferq li nav devokan binivîsin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:44, 7 tîrmeh 2026 (UTC) ::@[[Bikarhêner:Bikarhêner|Bikarhêner]] fikr? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:44, 15 tîrmeh 2026 (UTC) :::Formata ku te teklîf kirîye jî ne xerab e, baş tê xuyan. Feqet bi min halê berê (mewcûd) baştir e. Ji ber ku ev şablon (ku-tewîn-nav) bi piranî kurt in û ji bo her kesî ne mihîm e, lewma li kinarê bi formeke hebe ku karibe were vekirin û girtin baştir e. Lê belê ger şablon dirêjtir bin, em karin wekî ya wîkîya almanî bikin (ew jî wekî teklîfa te ye). -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 15 tîrmeh 2026 (UTC) == Reşwî == Silav ji we gî re, Pirsekê min heye. Ez difikirim şablonekê din çê bikim boy devokek kurmancî, yê êla Reşwî. Ew lêkerên xwe hinek cuda ditewînin. Mesela te hem "ez dikim" bêjî yan jî "ez dikime", "em dikinî, em tênî, te em kuştinî" (ne "em dikin") dema xwe yek in lê maneyên xwe ne yek in, "ez bikim" "ez ê bikim" "ez bikime" û dewamên xwe hemû demên xwe yek in lê mane dîsa ne yek in. Eger min çê kir, şûna xwe li ku derê tînim? Ez difikirim li tewandina devokên kurdî yê ku "tabên" xwe hene "kurmancîya rojavayî", "kurmancîya standard" hsw. Lê tewandin ewqes cuda ye dixwaze ku wî şablona tewandina kurdî pir were guherîn. Hûn çi dibêjin? (R: Hûn dewên çi?) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:38, 7 tîrmeh 2026 (UTC) :{{silav|Kurdanparez}} Binêre mînaka devoka ''rojhilatî'': [[Modul:ku-tewandin#L-135]] / [[Modul:ku-tewandin#L-138|L138]] / [[Modul:ku-tewandin#L-143|L-143]], .. Di nav modula ''ku-tewandin"-ê de tê çêkirin. [[Gotûbêja modulê:ku-tewandin#Paşgirên lêkeran di kurmanciya rojhilatî de]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:09, 7 tîrmeh 2026 (UTC) ::PS: Dema niha: [[Modul:ku-tewandin#L-128]]; dema borî: [[Modul:ku-tewandin#L-153]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:15, 7 tîrmeh 2026 (UTC) :::Merheba @[[Bikarhêner:Ghybu|Ghybu]], Eger mimkin be tu dikarî yên devokî têxî binmodulekê û bila modul load bike, bi vî awayî belkî çêkirina yên nû û famkirina modulê hêsantir be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:09, 7 tîrmeh 2026 (UTC) :::Lê di devokê reşwî de hem dema niha yê statîk heye (Îng: I do -> Ez dikim) û yê progressîf heye (I am doing -> Eîz (nêr) Ez î (mê) dikime, yan jî Ez î dikime/Ez ê dikime). Reşwî ji yê standardê pirtir bo zayend ferq tîne, hem jî li dema pêşî (Ez ê bikim (Nêr) ez a bikim (Mê)). Dema pêşî jî formên cuda hene (Ezêk bikime (I will be doing it) û ez ê/a bikim (I will do it)) :::Ev di modûlê têhel bê? [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:09, 8 tîrmeh 2026 (UTC) == WF:Xebat == Min sayfeya [[WF:Xebat]] çêkir, xeletiyên ku hûn ferq dikin ji kerema xwe lê zêde bikin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:35, 15 tîrmeh 2026 (UTC) == Modul:quote == @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]], @[[Bikarhêner:Keyomerd|Keyomerd]], @[[Bikarhêner:Ferhengvan|Ferhengvan]] Merheba, ez modula îngilîzî ya jêgirtin û çavkaniyan li gorî şablonên {{ş|jêder}} format dikim û ji bo ku hertişt wekî formata me ya niha be, gelek serê min diêşe. Ez dibêjim bila em dev ji formata niha berdin wekî ya îngilîzî bi kar bînin ji ber ku gelek xisûsiyetên îngilîzî hene ku yekî dikare biemilîne. Hûn ê bibêjin niha ji kû hat bîra tê, min got [[Wîkîferheng:Xebat#MediaWiki:Gadget-start.js|start.js]] nû bikim û min dît otomatîk çavkanî bi riya [[mw:Citoid]]ê bi riya DOI, ISBN û lînk tê çêkirin, min got wiya jî li skrîptê îlawe bikim loma min [[Wîkîferheng:Xebat#Mediawiki:Gadget-citoid-helper.js|Mediawiki:Gadget-citoid-helper.js]] hazir kir lê hin parametreyên Citoidê kêm bûn, min got ka wana rast bikim, min dît formata me ya niha ti standard bi kar nayîne tenê parametreyan bi virgulê li hev dixe. Ez dibêjim formata îngilîzî baştir e, hem ne îtalîk e ku bi hêsanî tên xwendin, hem jî tarîx û çavkanî herî pêşî tên nîşandan ku ji bo peyitandinê bo min muhîm e. Modula îngilîzî de hema bêje her tişt hatiye çêkirin, eger em rûnin tenê yên lazim li şablona çavkaniyên xwe binivîsin ew ê gelek wext bistîne. Eger em modula îngilîzî bi kar bînin, em ê hem karibin şablonên îngilîzî bi hêsanî û rast kopî bikin hem jî kurdîkirina parametreyan gelek hêsan e. Fikir? --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:20, 24 tîrmeh 2026 (UTC) : Ji bo miqayesekirinê bnr. [[:en:Template:quote-book]] / [[Şablon:jêder-kitêb/ceribandin]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:32, 24 tîrmeh 2026 (UTC) ::Bi min bila yê mewcûd jî bimîne, ew jî şiklen xweş û baştir e. Feqet bi min jî yên îngilîzî rehettir in, eger rastkirina yê mewcûd zehmet be, em rasterast wan ji xwe re bînin û tercime bikin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:41, 24 tîrmeh 2026 (UTC) :::Ez êvarê ve dixebitim, min nêzîk kiribû lê min got belkî hûn qane bibin lê xuya ye hûn ê hîn serê min gelek biêşînin {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:59, 24 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Bikarhêner|Bikarhêner]] û @[[Bikarhêner:Ghybu|Ghybu]] Eger îtîrazek tinebe, ez ê îtalîk ji jêgirtinê rakim... Jixwe bi riya [jêgirtin] dikare were veşartin û her daim bi * dest pê dike loma bi hêsanî tê fêmkirin û xwendin rihettir dibe. Bnr. [https://ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:ceribandin/nim%C3%BBne&oldid=6277132#L%C3%AAker_2 ceribandinê] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:13, 24 tîrmeh 2026 (UTC) == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 tîrmeh 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == ''mê'' yan ''nêr'' li gorî maneyê / ''mê'' yan ''nêr'' (bikaranîn dudil e) == [//ku.wiktionary.org/w/index.php?title=xelat&diff=prev&oldid=6291766]: Mixabin pirr bikarhêner şûnda parametreya <code>z=m/n</code> ('' m yan n li gorî maneyê'') <code>z=mn</code> (''m yan n (bikaranîn dudil e)'') bi kar tînin ([[Şablon:navdêr#Parametre]]) ji ber ku di nav her du nivîsê de pir ferq nebînin. Nizanim em ê dîsa parametreya <code>z=nt</code> (''nêtar'') çêkin, wekî berê: [//ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:D%C3%AEwan/ar%C5%9F%C3%AEv_2019&oldid=6104681#Zayend]. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 00:17, 28 tîrmeh 2026 (UTC) :Merheba {{r|Ghybu}} {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=mn}}</nowiki>}} Ya din jî; {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=m/n}}</nowiki>}} Tu dixwazî em wana berevajî bikin? Not: nêtar ji bo kurmancî nabe, mn û m/n baş in. Berê ji ber ku m/n tinebû, her kes li gorî parametreyên heyî dixebitî. Niha hene bi min problem nîne eger em berevajî nekin.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:32, 28 tîrmeh 2026 (UTC) : Bi min ev format baştir e: {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c1=m|c1etîk=Mêrdîn|c2=n|c2etîk=Dihok}}</nowiki>}} Yan jî: {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|zayend|c1=n|c2=m|c1ref={{Jêgirtin/Celadet Alî Bedirxan/HAWAR Cild 1 Hejmar 1-23 (1932-1933)/1998|hejmar=4|sal=1938}}|c2ref={{Zana Farqînî}}}}</nowiki>}} {{çavkanî}} :--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:49, 28 tîrmeh 2026 (UTC) f0aqevpw7t9dg5dj1xvafke73hj4rcm 6291816 6291815 2026-07-28T06:00:27Z Wikihez 7344 /* mê yan nêr li gorî maneyê / mê yan nêr (bikaranîn dudil e) */ Bersiv 6291816 wikitext text/x-wiki <noinclude>{{Dîwan/arşîv-ser|2026}}</noinclude> {{clear}} == Daxwazên standardkirinê == https://ku.wiktionary.org/wiki/W%C3%AEk%C3%AEferheng:Daxwaz%C3%AAn_standardkirin%C3%AA, Gelo di vê malperê de peyvên hatîye standart kirin; ji malperê rakin? Zêde tehlîhev e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:03, 8 kanûna paşîn 2026 (UTC) :@[[Bikarhêner:Rewiye tine|Rewiye tine]] [[Taybet:Tercîh#mw-prefsection-gadgets]] li vir amûra [[MediaWiki:Gadget-aWa.js/belgekirin|awa]] aktîv bike û pê re dikarî gotûbêjan arşîv bikî. Li sayfa [[WF:DS]] li kêleka her sernavê gotûbêjê <nowiki>[arşîv bike]</nowiki> derdikeve, pê lê bike û ew ê arşîv bike. Eger nikarî tu tenê şablona {{ş|ds-kirî}} îlawe bike, ez ê dûre arşîv bikim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:35, 5 tîrmeh 2026 (UTC) == Standartkirin == Sala borî, min pêşnîyazek kiribû. Halî hazir piştî daxwaza standarkirinê em du heftî disekinin, eger kesek fikrek dîyar neke. Raste rast peyv li gor ferhenga standart a mezopotamyayê tê standart kirin. Ji xwe sazîyek vê karî dike çima em vê barî dikin stuyê xwe. Mesela ez çaxe di wîkîferhengê de peyvek digêrim; standart a peyvê jî li cem xwe kontrol dikim. Eger destûr hebe bi germî dikarim wê malperê standart bikim. Benda bûna du heftîyan gelo ne zehmet e? Duyemîn pêşnîyaza min nîşandana standarta peyvê di malpera de ye. Kesek dema malperan binêre, divê li jora malperan bibîne ku ev peyv standart e. Ev jî hîzmet e. Çimkî nivîskar, wergêr, edîtor, rojnemavan hez dikin bi peyvê standart binivîsin. https://ku.wiktionary.org/wiki/k%C3%AAf li vir wekî mînak min daye nîşan. Lê îfade eger wisa be: Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r. 253) e yê çetir be. Çimkî îfadeya berê de peyva kurdî-tirkî derbas dibe û di mejîyê mirov de tevlihevî çêdibe.@[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Guherto|Guherto]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 10:25, 8 kanûna paşîn 2026 (UTC) :Merheba. Hevalno dîyar e karê standarkirinê li wîkîferhengê rawestîya ye. Min sê peyv ji bo standartkirinê qeyd kir. Kes li ser şîrove nenivîsî. Mehek jî li ser derbas bû. Aniha ez dikarim van rupelan biguherim. Li gor qaîdeya hatine danîn wisa ye. Daxwaza min heta niha jî ew e kelîmeyên di ferhenga standartkirinê de heyî divê em bikaribin rasterast li vir jî bikin standart. An jî demê kurttir bikin. Li weqfa mezapotamyayê 20 mirov digêhin hev li ser peyvekî seetan nîqaş dikin. Ma hewceyê em jî li vir nîqaş bikin? Tevlî vê jî ji xwe kes li ser vê mijare nasekîne van dema. Xeynî vê pêşnîyaza min nîşandana standarta peyvê di malpera de hebû. Li ser malperê 'Standarda Rastnivîsîna Ferhenga Kurdî a Weqfa Mezopotamyayê kêf (r.253) e' Tiştek mîna wî hebe yê gelek kêrî her cure nivîskarê me were. Çimkî hin nivîskarên me hez dike bi kelîmeyên standart binivîse. Di malperê de bila vê hêsanî fam bike çêtir e. @[[Bikarhêner:Bikarhêner|Bikarhêner]]@[[Bikarhêner:Ghybu|Ghybu]] [[Bikarhêner:Rewiye tine|Rewiye tine]] ([[Gotûbêja bikarhêner:Rewiye tine|gotûbêj]]) 18:35, 17 sibat 2026 (UTC) ::Merheba @[[Bikarhêner:Rewiye tine|Rewiye tine]]. Ev format pir xirab dibe. Tu dikarî li beşa Çavkaniyê binivîsî bi şablona {{ş|kitêb}} binivîsî çêtir e û tê eynî maneyê. Lê her kes standarda Weqfa Mezopotamyayê qebûl nakin û ez jî şibhê dikim ku ev websîte bi awayekî kolektîv tê çêkirin an na. Loma em bi ya kitêba rastnivisînê çêkin û eger îtîraz tinebe, şablona {{ş|ds-kirî}} li gotûbêja [[WF:DS]] binivîse, dûre li gotûbêjê arşîv bike, ne hewce ye li hêviya kesên din bisekinî. Eger itirazek hebe, ê ku dixwaze dûre dîsa şablona ds zêde bike. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:30, 5 tîrmeh 2026 (UTC) :::[https://berwarnews.com/ferhenga-rastnivisine-qonaxeke-giring-a-standardkirina-kurmanci-ye/ Roportaja Mikail Bülbül] li ser proseya standardkirinê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:57, 9 tîrmeh 2026 (UTC) ::::Min nû dît an jî nû hatiye zêdekirin lê meqaleyek bi navê [https://www.ferhengkurdi.com/?q=iltihap&modal=lijne lijneya edîtorîyê] nivîsandine [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:40, 22 tîrmeh 2026 (UTC) == <span lang="en" dir="ltr">Annual review of the Universal Code of Conduct and Enforcement Guidelines</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> I am writing to you to let you know the annual review period for the Universal Code of Conduct and Enforcement Guidelines is open now. You can make suggestions for changes through 9 February 2026. This is the first step of several to be taken for the annual review. [[m:Special:MyLanguage/Universal Code of Conduct/Annual review/2026|Read more information and find a conversation to join on the UCoC page on Meta]]. The [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee|Universal Code of Conduct Coordinating Committee]] (U4C) is a global group dedicated to providing an equitable and consistent implementation of the UCoC. This annual review was planned and implemented by the U4C. For more information and the responsibilities of the U4C, [[m:Special:MyLanguage/Universal Code of Conduct/Coordinating Committee/Charter|you may review the U4C Charter]]. Please share this information with other members in your community wherever else might be appropriate. -- In cooperation with the U4C, [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]])<section end="announcement-content" /> </div> 21:02, 19 kanûna paşîn 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=29905753 --> == Request for comment (global AI policy) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies for writing in English. {{int:Please-translate}} A [[:m:Requests for comment/Artificial intelligence policy|request for comment]] is currently being held to decide on a global AI policy. {{int:Feedback-thanks-title}} [[Bikarhêner:MediaWiki message delivery|MediaWiki message delivery]] ([[Gotûbêja bikarhêner:MediaWiki message delivery|gotûbêj]]) 00:58, 26 nîsan 2026 (UTC) </bdi> <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30424282 --> == Guharto == : <small>→ Ji rûpela ''[//ku.wiktionary.org/w/index.php?title=Got%C3%BBb%C3%AAj:berf%C3%AEtik&oldid=6233338 Gotûbêj:berfîtik]'' hatiye girtin.</small> Silav {{r|Ghybu}} ma hewce ye em guhartoyan jî kategorîze bikin? Li vê [[ژیشک]] binere, tije guhartoyên wê hene, ku em ji gişan re guhandar binivîsin dê 10 navên heman hebin di nav wê kategorîyê de. Tu çi difikirî? [[Bikarhêner:Keyomerd|Keyomerd]] ([[Gotûbêja bikarhêner:Keyomerd|gotûbêj]]) 09:40, 26 nîsan 2026 (UTC) :{{silav|Keyomerd}}. Erê, problem çî ye? {{=)}} Ew jî tên bikaranîn... Dema ku peyvek tê çêkirin hewce ye ku em hemû agahiyên wan binivîsin: bilêvkirin, bikaranîn, mînak, terîm, herêm, tewandin, etîmolojî... :Bi min peyvên ku wekî ''guherto'' hatine nivîsandin bi nivîsa {{w|Italic type|îtalîk|ziman=en}} (xwahr) di nav kategoriyan de werin nişan kirin (ji bo cudakirinê). {{ping|Ferhengvan|Bikarhêner}} [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:40, 30 nîsan 2026 (UTC) ::Yên '''''nestandard''''' di kategorîyan de biferq werin nîşandan baştir e. Qene em karibin wan ji yên stadard ferq bikin. @[[Bikarhêner:Ghybu|Ghybu]] Xêra xwe hûn sîstemeke wisa çêkin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 14:36, 1 gulan 2026 (UTC) :::Merheba @[[Bikarhêner:Keyomerd|Keyomerd]] û @[[Bikarhêner:Bikarhêner|Bikarhêner]] ev xisûsiyet jixwe di şablonên rêzimanê de heye, wextê {{param|formaalt|1}} dinivîsin, made dikeve Kategoriya [[:Kategorî:Formên alternatîv bi kurmancî]] li gorî koda zimanî jî zimanên din tê çêkirin. Hemû madeyên kurmancî bi alfabeya erebî dikevin vê kategoriyê lê nizanim ev tiştekî rast e Yan xelet e, ji bo nîşandanê min çêkiribû lê min hîn wext nedît ku nîqaşek li ser çêkim. Qaîdeyên bikaranîna vê parametreyê di wîkiya îngilîzî de jî tam ne belî ye. Du gotûbêj [https://en.wiktionary.org/wiki/Wiktionary:Requests_for_moves,_mergers_and_splits#Category:Alternative_forms_by_language] [https://en.wiktionary.org/wiki/Wiktionary:Beer_parlour/2024/June#Decluttering_the_altform_mess] çêkirine lê ji bo îngilîzî ev parametre nehatiye bikaranîn. Min ji bo nîşandanê niha [https://ku.wiktionary.org/w/index.php?title=bax%C3%A7%C3%AA_zarokan&diff=prev&oldid=6241372] ceriband lê bi min xelet e. Em çawa bikin? Kengî vê parametreyê bi kar bînin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:29, 8 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Tu çi difikirî? Ji bo zazakî [https://ku.wiktionary.org/w/index.php?title=a_c%C4%B1_geyrayene&oldid=6241396 wisa] bikin? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:55, 8 tîrmeh 2026 (UTC) :::::Kategorîyekê cuda baş dibe. Wextê ku ez li kategorîya "lekêren bi zazakî" dinêrim, ez hem formê bi şikilê Johnsonê û formê standardê dibînim. Zaten wexte ku ez dikevim ê Johnsonê, min dibe formê standardê. Kategorîyekê cuda, bi taybetî ji bo nivîsandinên alternatîf, baş dibe. :::::Lê em bîr nekin ku wextê ku em bo formên alternatîf yên devokî qal dikin, belkî adil neye ku em ev bişînin derekê din yê ku însan ewqas nabînin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:03, 8 tîrmeh 2026 (UTC) ::::::@[[Bikarhêner:Kurdanparez|Kurdanparez]] Gelo min rast fêm kir? Tu dibêjî formên {{q|ku|kîvroşk}} bi dîqet werin guhartokirin lê bi yên bi alfabeya Jacobsonê hemû bikin {{param|formaalt|1}}? Formên Jacobsonê dê bikevin Kategoriya [[:Kategorî:Lêker bi zazakî|Lêker bi zazakî]] û [[:Kategorî:Lema bi zazakî|Lema bi zazakî]] yan na? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:55, 8 tîrmeh 2026 (UTC) :::::::Bi min naxwaze di wan kategoriyan de bikeve. Wek tu dibînî dûplîkat pir hene. Bi min çareya baştir yên Johnsonê di katehgorîyekê din bikevin (bila format li rûpelan neyin guherandin, bi tenê kategorî) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 00:37, 9 tîrmeh 2026 (UTC) == Peyvên soranî bi latînî ([[:Kategorî:Soranî]]) == Silav, di nav vê kategoriyê (''[[:Kategorî:Soranî]]'') de pirr peyv tenê bi alfabeya latînî hatine nivîsandin. Divê ew mutleq jî bi alfabeya erebî werin transkrîbe kirin ji ber ku soranî bi alfabeya erebî tê nivîsand... Bikarênerên ku soranî dizanin dikarin wan sererast bikin? Mînakên guhertinan: [//ku.wiktionary.org/w/index.php?title=zor%C3%AEne&curid=6584&diff=6233355&oldid=5859303], [//ku.wiktionary.org/w/index.php?title=s%C3%AAw&diff=6233097&oldid=6233003], [//ku.wiktionary.org/w/index.php?title=sewz&diff=6233313&oldid=6069107], ... Spas! [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 01:16, 2 gulan 2026 (UTC) == <span lang="en" dir="ltr">Vote now in the 2026 U4C election</span> == <div lang="en" dir="ltr"> <section begin="announcement-content" /> Eligible voters are asked to participate in the 2026 [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee|Universal Code of Conduct Coordinating Committee]] election. More information–including an eligibility check, voting process information, candidate information, and a link to the vote–are available on Meta at the [[m:Special:MyLanguage/Universal_Code_of_Conduct/Coordinating_Committee/Election/2026|2026 Election information page]]. The vote closes on 2 June 2026 at [https://zonestamp.toolforge.org/1780358400 00:00 UTC]. Please vote if your account is eligible. Results will be available by 14 June 2026. -- In cooperation with the U4C,<section end="announcement-content" /> </div> [[m:User:Keegan (WMF)|Keegan (WMF)]] ([[m:User talk:Keegan (WMF)|talk]]) 17:15, 27 gulan 2026 (UTC) <!-- Message sent by User:Keegan (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == RFC about AI-generated content in Wikimedia Commons == <bdi lang="en" dir="ltr">Apologies for writing in English, please help translate this message to your language. You are invited to participate in a [[c:Commons:Requests for comment/Policy update for AI content|request for comment on Wikimedia Commons about a policy update for AI content]]. This may affect files that are uploaded to Wikimedia Commons for use on this project. Thank you. [[m:User:Codename Noreste|Codename Noreste]] ([[m:User talk:Codename Noreste|gotûbêj]])</bdi> 17:12, 23 hezîran 2026 (UTC) <!-- Message sent by User:Codename Noreste@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == <span lang="en" dir="ltr">Deployment of Legal and Safety Contacts Link in the Footer of Your Wiki</span> == <div lang="en" dir="ltr"> <section begin="Message"/> '''Legal & Safety Contacts''' Hello community, the Wikimedia Foundation has provided a [[wmf:Special:MyLanguage/Legal:Wikimedia Foundation Legal and Safety Contact Information|single legal and safety contact page]], to be linked in the footer of your wiki, to ensure access to accurate legal information. This is a regulatory requirement. We have already rolled out links to English, German, Italian, Spanish and other wikis and we will deploy to your wiki soon. [[m:Special:MyLanguage/Wikimedia_Foundation_Legal_and_Safety_Contacts_FAQ|Please read more on the project page]] and leave any comments in this thread or on the [[m:Special:MyLanguage/Talk:Wikimedia Foundation Legal and Safety Contacts FAQ|talk page]]. <section end="Message"/> </div> -- [[User:Sannita (WMF)|User:Sannita (WMF)]] ([[User talk:Sannita (WMF)|talk]]) 13:31, 25 hezîran 2026 (UTC) <!-- Message sent by User:Sannita (WMF)@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=User:Sannita_(WMF)/Mass_sending_test&oldid=30731267 --> == Jêbirina ferhenga Sadallah == Merheba @[[Bikarhêner:Guherto|Guherto]] Îmkan heye lîsteyeke wisa çêkî ku hemû sayfeyên Cyrusbot çêkir yên ku tê de tenê tercimeyeke îngilîzî heye û ev tercime jî hatibe jêbirin? Nimûne ''[[derdzanî]], [[êşzanî]]'' tenê tercimeya [[pestology]] heye ew jî ji ber heqê telîfê hatiye jêbirin. Nimûneyeke din ''zêrrgeh'', ''zêrrkar'' [[goldsmith]] hatiye jêbirin zêr wekî zêrr hatiye guhartin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:48, 26 hezîran 2026 (UTC) == Beşa Tewandin bo kurmancî == Bi ya min şablona {{ş|ku-tewîn-nav}} û ya fiîlê em bixin beşa Tewandinê (wekî [[şodir|zazakî]]. Bi vî awayî hem ji aliyê şiklî ve hem jî ji aliyê bikaranînê ve xweştir xuya bike. Eger di qismê Tewandinê de be, ê ku dixwaze îzah û notên xwe yan jî emilandinên din jî dikare binivîse. Hûn çi dibêjin? @[[Bikarhêner:Ferhengvan|Ferhengvan]], @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:05, 6 tîrmeh 2026 (UTC) :Belkî em dikarin Formata şiweyan wekî ya behdînî jî têxin nav şablonê. Pir caran şiklê tabloya Tercimeyan ji ber dirêjbûna şablona teqînê jî xirab dibe wekî [[astrofizîk]]. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 6 tîrmeh 2026 (UTC) :Min mijarê te li jorê yê xwe dît, fikirên min jî hene eger baş e. Yê ku te gotiye bi min baş dibe, ji ber ku her rûpel ji vê mîna hev dibe. Em ê rindtir jî ferq li nav devokan binivîsin. [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:44, 7 tîrmeh 2026 (UTC) ::@[[Bikarhêner:Bikarhêner|Bikarhêner]] fikr? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 08:44, 15 tîrmeh 2026 (UTC) :::Formata ku te teklîf kirîye jî ne xerab e, baş tê xuyan. Feqet bi min halê berê (mewcûd) baştir e. Ji ber ku ev şablon (ku-tewîn-nav) bi piranî kurt in û ji bo her kesî ne mihîm e, lewma li kinarê bi formeke hebe ku karibe were vekirin û girtin baştir e. Lê belê ger şablon dirêjtir bin, em karin wekî ya wîkîya almanî bikin (ew jî wekî teklîfa te ye). -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:50, 15 tîrmeh 2026 (UTC) == Reşwî == Silav ji we gî re, Pirsekê min heye. Ez difikirim şablonekê din çê bikim boy devokek kurmancî, yê êla Reşwî. Ew lêkerên xwe hinek cuda ditewînin. Mesela te hem "ez dikim" bêjî yan jî "ez dikime", "em dikinî, em tênî, te em kuştinî" (ne "em dikin") dema xwe yek in lê maneyên xwe ne yek in, "ez bikim" "ez ê bikim" "ez bikime" û dewamên xwe hemû demên xwe yek in lê mane dîsa ne yek in. Eger min çê kir, şûna xwe li ku derê tînim? Ez difikirim li tewandina devokên kurdî yê ku "tabên" xwe hene "kurmancîya rojavayî", "kurmancîya standard" hsw. Lê tewandin ewqes cuda ye dixwaze ku wî şablona tewandina kurdî pir were guherîn. Hûn çi dibêjin? (R: Hûn dewên çi?) [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 11:38, 7 tîrmeh 2026 (UTC) :{{silav|Kurdanparez}} Binêre mînaka devoka ''rojhilatî'': [[Modul:ku-tewandin#L-135]] / [[Modul:ku-tewandin#L-138|L138]] / [[Modul:ku-tewandin#L-143|L-143]], .. Di nav modula ''ku-tewandin"-ê de tê çêkirin. [[Gotûbêja modulê:ku-tewandin#Paşgirên lêkeran di kurmanciya rojhilatî de]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:09, 7 tîrmeh 2026 (UTC) ::PS: Dema niha: [[Modul:ku-tewandin#L-128]]; dema borî: [[Modul:ku-tewandin#L-153]] [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 13:15, 7 tîrmeh 2026 (UTC) :::Merheba @[[Bikarhêner:Ghybu|Ghybu]], Eger mimkin be tu dikarî yên devokî têxî binmodulekê û bila modul load bike, bi vî awayî belkî çêkirina yên nû û famkirina modulê hêsantir be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 15:09, 7 tîrmeh 2026 (UTC) :::Lê di devokê reşwî de hem dema niha yê statîk heye (Îng: I do -> Ez dikim) û yê progressîf heye (I am doing -> Eîz (nêr) Ez î (mê) dikime, yan jî Ez î dikime/Ez ê dikime). Reşwî ji yê standardê pirtir bo zayend ferq tîne, hem jî li dema pêşî (Ez ê bikim (Nêr) ez a bikim (Mê)). Dema pêşî jî formên cuda hene (Ezêk bikime (I will be doing it) û ez ê/a bikim (I will do it)) :::Ev di modûlê têhel bê? [[Bikarhêner:Kurdanparez|Kurdanparez]] ([[Gotûbêja bikarhêner:Kurdanparez|gotûbêj]]) 22:09, 8 tîrmeh 2026 (UTC) == WF:Xebat == Min sayfeya [[WF:Xebat]] çêkir, xeletiyên ku hûn ferq dikin ji kerema xwe lê zêde bikin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:35, 15 tîrmeh 2026 (UTC) == Modul:quote == @[[Bikarhêner:Ghybu|Ghybu]], @[[Bikarhêner:Bikarhêner|Bikarhêner]], @[[Bikarhêner:Keyomerd|Keyomerd]], @[[Bikarhêner:Ferhengvan|Ferhengvan]] Merheba, ez modula îngilîzî ya jêgirtin û çavkaniyan li gorî şablonên {{ş|jêder}} format dikim û ji bo ku hertişt wekî formata me ya niha be, gelek serê min diêşe. Ez dibêjim bila em dev ji formata niha berdin wekî ya îngilîzî bi kar bînin ji ber ku gelek xisûsiyetên îngilîzî hene ku yekî dikare biemilîne. Hûn ê bibêjin niha ji kû hat bîra tê, min got [[Wîkîferheng:Xebat#MediaWiki:Gadget-start.js|start.js]] nû bikim û min dît otomatîk çavkanî bi riya [[mw:Citoid]]ê bi riya DOI, ISBN û lînk tê çêkirin, min got wiya jî li skrîptê îlawe bikim loma min [[Wîkîferheng:Xebat#Mediawiki:Gadget-citoid-helper.js|Mediawiki:Gadget-citoid-helper.js]] hazir kir lê hin parametreyên Citoidê kêm bûn, min got ka wana rast bikim, min dît formata me ya niha ti standard bi kar nayîne tenê parametreyan bi virgulê li hev dixe. Ez dibêjim formata îngilîzî baştir e, hem ne îtalîk e ku bi hêsanî tên xwendin, hem jî tarîx û çavkanî herî pêşî tên nîşandan ku ji bo peyitandinê bo min muhîm e. Modula îngilîzî de hema bêje her tişt hatiye çêkirin, eger em rûnin tenê yên lazim li şablona çavkaniyên xwe binivîsin ew ê gelek wext bistîne. Eger em modula îngilîzî bi kar bînin, em ê hem karibin şablonên îngilîzî bi hêsanî û rast kopî bikin hem jî kurdîkirina parametreyan gelek hêsan e. Fikir? --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:20, 24 tîrmeh 2026 (UTC) : Ji bo miqayesekirinê bnr. [[:en:Template:quote-book]] / [[Şablon:jêder-kitêb/ceribandin]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:32, 24 tîrmeh 2026 (UTC) ::Bi min bila yê mewcûd jî bimîne, ew jî şiklen xweş û baştir e. Feqet bi min jî yên îngilîzî rehettir in, eger rastkirina yê mewcûd zehmet be, em rasterast wan ji xwe re bînin û tercime bikin. -- [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 09:41, 24 tîrmeh 2026 (UTC) :::Ez êvarê ve dixebitim, min nêzîk kiribû lê min got belkî hûn qane bibin lê xuya ye hûn ê hîn serê min gelek biêşînin {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:59, 24 tîrmeh 2026 (UTC) ::::@[[Bikarhêner:Bikarhêner|Bikarhêner]] û @[[Bikarhêner:Ghybu|Ghybu]] Eger îtîrazek tinebe, ez ê îtalîk ji jêgirtinê rakim... Jixwe bi riya [jêgirtin] dikare were veşartin û her daim bi * dest pê dike loma bi hêsanî tê fêmkirin û xwendin rihettir dibe. Bnr. [https://ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:ceribandin/nim%C3%BBne&oldid=6277132#L%C3%AAker_2 ceribandinê] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:13, 24 tîrmeh 2026 (UTC) == Request for comment (the future of Abstract Wikipedia) == <bdi lang="en" dir="ltr" class="mw-content-ltr"> Apologies if this has not yet been translated into your wiki's language. {{int:Please-translate}} You are invited to voice your opinions in a [[:m:Requests for comment/The future of Abstract Wikipedia|request for comment about the future of Abstract Wikipedia]]. {{Int:Feedback-thanks-title}} [[:m:User:Kowal2701|Kowal2701]] ([[:m:User talk:Kowal2701|talk]]) 12:25, 24 tîrmeh 2026 (UTC) </bdi> <!-- Message sent by User:DreamRimmer@metawiki using the list at https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=30513860 --> == ''mê'' yan ''nêr'' li gorî maneyê / ''mê'' yan ''nêr'' (bikaranîn dudil e) == [//ku.wiktionary.org/w/index.php?title=xelat&diff=prev&oldid=6291766]: Mixabin pirr bikarhêner şûnda parametreya <code>z=m/n</code> ('' m yan n li gorî maneyê'') <code>z=mn</code> (''m yan n (bikaranîn dudil e)'') bi kar tînin ([[Şablon:navdêr#Parametre]]) ji ber ku di nav her du nivîsê de pir ferq nebînin. Nizanim em ê dîsa parametreya <code>z=nt</code> (''nêtar'') çêkin, wekî berê: [//ku.wiktionary.org/w/index.php?title=W%C3%AEk%C3%AEferheng:D%C3%AEwan/ar%C5%9F%C3%AEv_2019&oldid=6104681#Zayend]. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 00:17, 28 tîrmeh 2026 (UTC) :Merheba {{r|Ghybu}} {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=mn}}</nowiki>}} Ya din jî; {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c=m/n}}</nowiki>}} Tu dixwazî em wana berevajî bikin? Not: nêtar ji bo kurmancî nabe, mn û m/n baş in. Berê ji ber ku m/n tinebû, her kes li gorî parametreyên heyî dixebitî. Niha hene bi min problem nîne eger em berevajî nekin.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:32, 28 tîrmeh 2026 (UTC) : Bi min ev format baştir e: {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|kelîme|c1=m|c1etîk=Mêrdîn|c2=n|c2etîk=Dihok}}</nowiki>}} Yan jî: {{demo|sep=wisa xuya dibe:<br>|<nowiki>{{navdêr|ku|zayend|c1=n|c2=m|c1ref={{Jêgirtin/Celadet Alî Bedirxan/HAWAR Cild 1 Hejmar 1-23 (1932-1933)/1998|hejmar=4|sal=1938}}|c2ref={{Zana Farqînî}}}}</nowiki>}} {{çavkanî}} :--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 05:49, 28 tîrmeh 2026 (UTC) ::Feqat em dikarin li şûna {{param2|c|m/n}}, {{param2|c|mn?}} yan {{param2|c|mn!}} çêkin ji bo ku neyên tevlihevkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 06:00, 28 tîrmeh 2026 (UTC) qrzqjiac67r287ssh5rjb74769j7oe2 Modul:ku-tewandin/tabloErgatîv 828 1357312 6291826 6275209 2026-07-28T11:18:49Z Ghybu 1393 girek 6291826 Scribunto text/plain -- [[Modul:ku-tewandin/tablo]] -- [[Modul:ku-tewandin/tabloGotar]] -- [[Tewandin:dîtin]] local conj = require('Modul:ku-tewandin') local lang = mw.getContentLanguage() local export = {} function export.tablo(frame) local args = frame:getParent().args local baseOpts = { isTransitive = false, isCompoundVerb = args['valahî'] or false, preSimpleVerb = args['pêşgir'] or '', postSimpleVerb = args['paşgir'] or '', overrideBi = args['bi'] or nil, overrideDi = args['di'] or nil, overrideNa = args['na'] or nil, overrideNe = args['ne'] or nil, impNegForm = nil, addPreverbParticles = 'na' -- Remove preverb particles (ê/dê) } local presentStems = {args['niha'], args['niha2'], args['niha3']} local pastStems = {args['borî'], args['borî2'], args['borî3']} local transitivity = args['form'] if (transitivity ~= 'gerguhêz' and transitivity ~= 'negerguhêz') then return '<span style="color:red">form = gerguhêz / negerguhêz</span>' end if (baseOpts.isCompoundVerb == 'erê') then baseOpts.isCompoundVerb = true else baseOpts.isCompoundVerb = false end -- Conjugation table in all tenses local concatPrs = false local infoTense = conj.conjugateAllTenses(baseOpts, presentStems, pastStems, 'positive', concatPrs) -- Negatives conjugations table local negInfoTense = conj.conjugateAllTenses(baseOpts, presentStems, pastStems, 'negative', concatPrs) -- Imperatrive form '2'; negative form with 'ne' baseOpts.impNegForm = 2 local impNegForm2 = conj.conjugateMultiStem(baseOpts, 'impPresent', presentStems, pastStems, 'negative').conj -- Construction of conjugation table whose dimensions change depending on -- whether it is a transitive verb or not; and whether there is a preverbParticle (yes or no). -- First, we create the table header, then the body (content). local function tenseTableHeader(tense) local nameKu = lang:ucfirst(infoTense[tense].nameKu) -- Kurdish name local nameEn = lang:ucfirst(infoTense[tense].nameEn) -- English name local tabHeader = function(col) local header = '\n! id="' .. infoTense[tense].name .. '"' .. 'class="' .. infoTense[tense].stemType .. '-stem tense-table-title" colspan="'.. col .. '" |' .. nameKu .. '- <small><i>-{'.. nameEn ..'}-</i></small>' .. '\n|-' return header end local preverbParticle = '' local tabH = tabHeader(4) if infoTense[tense].preverbParticle == "ê" then tabH = tabHeader(5) preverbParticle = '\n! class="agent-title" | ' end local tenseHeader = tabHeader(2) .. '\n! class="negative" | Erênî' ..'\n! class="positive" | Neyînî' .. '\n|-' if (infoTense[tense].stemType == "past" and transitivity == "gerguhêz") then tenseHeader = tabH .. '\n! class="agent-title" | Biker <span class="toggle-width">zêde <span class="arrow">›</span></span>' .. preverbParticle .. '\n! class="object-title" | Berkar' .. '\n! class="negative" | Erênî' .. '\n! class="positive" | Neyînî' .. '\n|-' end return tenseHeader end local function tenseTableBody(tense, pers) local preverbParticles = conj.getPreverbParticles(infoTense[tense].preverbParticle, infoTense[tense].stemType, false) local bila = '' if infoTense[tense].mode == "subjunctive" then bila = '<span style="color:gray">(bila) </span>' end local preverbParticle = '' if infoTense[tense].preverbParticle == "ê" then preverbParticle = '\n| class="particle" | (y)ê/dê' end local body = '\n|' .. bila .. conj.pronouns[pers] .. ' ' .. preverbParticles[pers] .. ' ' .. infoTense[tense].conj[pers] .. '\n|' .. bila .. conj.pronouns[pers] .. ' ' .. preverbParticles[pers] .. ' ' .. negInfoTense[tense].conj[pers] .. '\n|-' if (infoTense[tense].stemType == "past" and transitivity == "gerguhêz") then body = '\n| class="agent" |' .. bila .. conj.agents[pers] .. preverbParticle .. '\n| class="object" |' .. conj.pronouns[pers] .. '\n|' .. infoTense[tense].conj[pers] .. '\n|' .. negInfoTense[tense].conj[pers] .. '\n|-' end return body end -- Construction of the conjugation table for a given tense: the header -- and the body are combined. local function conjugateTable(tense) local tenseBody = '' local tenseHeader = tenseTableHeader(tense) for _, pers in ipairs(conj.order) do tenseBody = tenseBody .. tenseTableBody(tense, pers) end local tab = '\n{| cellpadding="2" class="tense-table"' .. '\n|-' .. tenseHeader .. tenseBody .. '\n|}' return tab end --Retrieving some parameters for creating the main table header local verb = args[1] or mw.title.getCurrentTitle().subpageText local preSimpleVerb = args['pêşgir'] or '' local postSimpleVerb = args['paşgir'] or '' -- Cureyê lêkerê local verbStruc = conj.verbStruct(baseOpts.isCompoundVerb, baseOpts.preSimpleVerb) if (verbStruc == 'preverbVerb') then verbStruc = 'pêkhatî' elseif (verbStruc == 'compoundVerb') then verbStruc = 'hevedudanî' else verbStruc = 'xwerû' end local prsStemsFormat = {} for _, stem in ipairs(presentStems) do if stem then prsStemsFormat[#prsStemsFormat+1] = preSimpleVerb .. '-' .. stem ..'-' end end local pstStemsFormat = {} for _, stem in ipairs(pastStems) do if stem then pstStemsFormat[#pstStemsFormat+1] = preSimpleVerb .. '-' .. stem ..'-' end end local prsStems = table.concat(prsStemsFormat, ' / ') .. postSimpleVerb local pstStems = table.concat(pstStemsFormat, ' / ') .. postSimpleVerb -- The negation in "me-" is deleted in the imperative when the accent is equal to "rojhilatî. local function rojhilatiNegForm(tags) if args['devok'] == 'rojhilatî' then return '' else return tags end end return '{| align="center" class="conj-table"' .. '\n|-' .. '\n| colspan="8" class="title" | Tewandina lêkera [[' .. verb .. ']]<br><span style="font-weight:normal;">(' .. verbStruc .. ', ' .. transitivity .. ')</span>' .. '\n|-' .. '\n! colspan="2" class="present-stem" | Rehê dema niha' .. '\n! colspan="6" style="font-weight:normal; text-align:center; border-bottom:dotted 1px grey;" | ' .. prsStems .. '\n|-' .. '\n! colspan="2" class="past-stem" | Rehê dema borî' .. '\n! colspan="6" style="font-weight:normal; text-align:center;" | ' .. pstStems .. '\n|-' .. '\n|' .. '\n|-' .. '\n| colspan="8" id="imp" class="mood" | Raweya fermanî - <small><i>Imperative</i></small>' .. '\n|-' .. '\n| colspan="8" valign="top" | ' .. '\n{| cellpadding="2" class="tense-table"' .. '\n|-' .. '\n| colspan="2" class="present-stem" style="border-top:1px dotted grey; border-bottom:1px dotted grey"| ' .. '\n|-' .. '\n! class="negative" | Erênî' .. '\n! class="positive" | Neyînî' .. '\n|-' .. '\n| valign="top" | <span style="color:gray">(tû)</span> ' .. infoTense.impPresent.conj.s2 .. '\n| valign="top" | <span style="color:gray">(tû)</span> ' .. impNegForm2.s2 .. rojhilatiNegForm('<br> <span style="color:gray">(tû)</span> ' .. negInfoTense.impPresent.conj.s2) .. '\n|-' .. '\n| valign="top" | <span style="color:gray">(hûn)</span> ' .. infoTense.impPresent.conj.p2 .. '\n| valign="top" | <span style="color:gray">(hûn)</span> ' .. impNegForm2.p2 .. rojhilatiNegForm('<br> <span style="color:gray">(hûn)</span> ' .. negInfoTense.impPresent.conj.p2) ..'\n|}' .. '\n|-' .. '\n| colspan="8" id="ind" class="mood" | Raweya pêşkerî - <small><i>Indicative</i></small>' .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indPresent') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indPreterite') .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indImperfect') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indPluperfect') .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indFuture') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indFuturePerfect') .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indPerfect') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('indNwPluperfect') .. '\n|-' .. '\n| colspan="8" id="subj" class="mood" | Raweya xwestekî - <small><i>Subjunctive</i></small>' .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('subjPresent') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('subjPreterite') .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('subjImperfect') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('subjPluperfect') .. '\n|-' .. '\n| colspan="8" id="cond" class="mood" | Raweya mercî - <small><i>Conditional</i></small>' .. '\n|-' .. '\n| colspan="4" valign="top" | ' .. conjugateTable('condPresent') .. '\n| colspan="4" valign="top" | ' .. conjugateTable('condPreterite') .. '\n|}' end return export oqbhstr5kqo8fnrafjtkuj5pk7pgi6o Wîkîferheng:Xebat 4 1357857 6291675 6291622 2026-07-27T16:49:12Z Ghybu 1393 /* MediaWiki:Gadget-jeder.js */ Bersiv 6291675 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) = Moda tarî = == MediaWiki:Newarticletext == * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) == Modul:dara kategoriyan == * [[Modul:dara kategoriyan]] link_box —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} feqat [[Modul:dara kategoriyan/zimankatbike]] çênabe. Claude serê xwar dîsa nebû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 26 tîrmeh 2026 (UTC) *::ew jî çêbû [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:35, 26 tîrmeh 2026 (UTC) == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) q3782fb8e7idl6jmr5rr9bhai6njifh 6291676 6291675 2026-07-27T17:09:17Z Wikihez 7344 /* MediaWiki:Gadget-jeder.js */ Bersiv 6291676 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) :::Ez niha bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6290820] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6290821#L-8] bi kar tînim ti problem nîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:09, 27 tîrmeh 2026 (UTC) = Moda tarî = == MediaWiki:Newarticletext == * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) == Modul:dara kategoriyan == * [[Modul:dara kategoriyan]] link_box —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} feqat [[Modul:dara kategoriyan/zimankatbike]] çênabe. Claude serê xwar dîsa nebû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 26 tîrmeh 2026 (UTC) *::ew jî çêbû [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:35, 26 tîrmeh 2026 (UTC) == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) axj9lq5vxguhacoh2npcrghxn0woe7o 6291781 6291676 2026-07-28T02:18:02Z Wikihez 7344 /* Moda tarî */ 6291781 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) :::Ez niha bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6290820] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6290821#L-8] bi kar tînim ti problem nîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:09, 27 tîrmeh 2026 (UTC) = Moda tarî = == [[MediaWiki:Newarticletext]] == * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) == [[Modul:dara kategoriyan]] == * [[Modul:dara kategoriyan]] link_box —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} feqat [[Modul:dara kategoriyan/zimankatbike]] çênabe. Claude serê xwar dîsa nebû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 26 tîrmeh 2026 (UTC) *::ew jî çêbû [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:35, 26 tîrmeh 2026 (UTC) == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) qpfulmnw8cv3l41lq5hopva21lvz0pt 6291782 6291781 2026-07-28T02:18:28Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina 2 madeyan li [[Wîkîferheng:Xebat/arşîv 1]], [[Wîkîferheng:Xebat/arşîv 1]] 6291782 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) :::Ez niha bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6290820] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6290821#L-8] bi kar tînim ti problem nîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:09, 27 tîrmeh 2026 (UTC) = Moda tarî = == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) smfhcsvlhz9cfn50dq6hu796imo4i49 6291786 6291782 2026-07-28T02:24:46Z Wikihez 7344 Restored revision 6291781 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291786 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) :::Ez niha bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6290820] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6290821#L-8] bi kar tînim ti problem nîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:09, 27 tîrmeh 2026 (UTC) = Moda tarî = == [[MediaWiki:Newarticletext]] == * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) == [[Modul:dara kategoriyan]] == * [[Modul:dara kategoriyan]] link_box —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} feqat [[Modul:dara kategoriyan/zimankatbike]] çênabe. Claude serê xwar dîsa nebû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 26 tîrmeh 2026 (UTC) *::ew jî çêbû [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:35, 26 tîrmeh 2026 (UTC) == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) qpfulmnw8cv3l41lq5hopva21lvz0pt 6291787 6291786 2026-07-28T02:25:05Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina 1 madeyê li [[Wîkîferheng:Xebat/arşîv 1]] 6291787 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) :::Ez niha bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6290820] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6290821#L-8] bi kar tînim ti problem nîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:09, 27 tîrmeh 2026 (UTC) = Moda tarî = == [[Modul:dara kategoriyan]] == * [[Modul:dara kategoriyan]] link_box —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} feqat [[Modul:dara kategoriyan/zimankatbike]] çênabe. Claude serê xwar dîsa nebû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 26 tîrmeh 2026 (UTC) *::ew jî çêbû [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:35, 26 tîrmeh 2026 (UTC) == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) dccrgwo07vff5wi07ptc81q34hqty41 6291790 6291787 2026-07-28T02:25:14Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina 1 madeyê li [[Wîkîferheng:Xebat/arşîv 1]] 6291790 wikitext text/x-wiki {{/ser}} = Karên ferhengî = == Mane == * [[:Kategorî:Madeyên bê beşa mane]] ** [[:Kategorî:Madeyên bê beşa mane bi kurmancî]] Li ser van rûpelan ev made hene ku maneyan wan nehatine nivîsin û divê werin nivîsin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Etîmolojî == *[[:Kategorî:Daxwazên etîmolojiyê]] **[[:Kategorî:Daxwazên etîmolojiyê bi kurmancî]] Li ser van rûpelan ev made hene ku etîmolojiya wan hîn nehatine nivîsin. Ji bo alîkariyê binêre [[WF:Etîmolojî]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Cureyê rêzimanî == * [[:Kategorî:Gotarên bê kategoriya rêzimanî]] * [[:Kategorî:Gotarên bê kategoriya rêzimanî bi kurmancî]] Li ser van rûpelan ev made hene ku cureyên wan yên rêzimanî hîn nehatine nivîsin. Ji bo alîkariyê binêre [[Alîkarî:Cureyên peyvan]] —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Kontrol == * [[:Kategorî:Kontrol]] ** [[:Kategorî:Kontrola maneyê]] Ev madde bi botê hatine çêkirin, yek bi yek divê werin kontrolkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Şablon = == IPA == * {{ş|IPA}} divê [[Modul:IPA]] bi kar bîne. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Deng == Kurdîkirina belgekirina {{ş|deng}} lazim e.--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:06, 19 tîrmeh 2026 (UTC) = Modul = == Modul:form of/templates == * [[Modul:form of/templates]]: Divê ev modul were rojanekirin û xeletiyên berê wekî ([[hevalê]]) werin rastkirin. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:Merheba @[[Bikarhêner:Ghybu|Ghybu]] Te gotibû di vê modulê de xeletî hene, jkx tu dikarî li vir binivîsî çi kêmasî hene, daku wextê rojane dikim ez ji bîr nekim? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:16, 21 tîrmeh 2026 (UTC) *::Silav. Nizanim ji bîra min çûye... Herwiha ji bo çêkirina formên navdêran zanînên cîns û tîpa dawî bes e: *::* (-ê, mê) => çemandî, bangkirin *::* (-ê, nêr) => îzafe *::* (-ê, mê û nêr) => îzafe (nêr), bangkirin (mê), çemandî (mê) *::* (-a) => îzafe (mê) *::* (-ekî) => îzafe û çemandî (nêr, nebinavkirî) *::* (-eke) = > îzafe (mê, nebinavkirî) *::* ... *:: <code>if find(mw.title.getCurrentTitle().subpageText, 'ekî$') then ... end</code> *::<code><nowiki>{{ku-tewîn-navForm|<navdêr>|<zayend>}</nowiki></code> *::Tablo û nivîs di yekcarî de tên çêkirin... *::Feqet problem lêzêdekirina mînakan e. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 17:34, 21 tîrmeh 2026 (UTC) *:::Lêzêdekirina kîjan nimûneyan? Ev koda js ji bo çi ye? Qisûrê nenêre min fêm nekir :/ [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:13, 21 tîrmeh 2026 (UTC) *::::Li vira ([[hevalê#Formeke navdêrê]]) di bin maneyên 1. û 2. mînak nayên tevlî kirin :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:18, 21 tîrmeh 2026 (UTC) *:::::Ev tercîh e, ne mecbûrî ye, em dikarin [https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&diff=prev&oldid=6276350 wisa] bikin. Wekî din? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:29, 21 tîrmeh 2026 (UTC) *::::::Min li jor tênê got ku tenê parametreyên "navdêr" û "zayend" hewce nee. Bi '''[//ku.wiktionary.org/w/index.php?title=heval%C3%AA&curid=969734&diff=6276353&oldid=6276350 vî]''' awayî jî tê çêkirin. Parametreyên din ne hewce ne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 18:38, 21 tîrmeh 2026 (UTC) *:::::::Ji bo wê şabloneke din lazim e, bila ev şablon wekî îngilîzî bimîne em ji bo kurmancî yekî din çêkin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:42, 21 tîrmeh 2026 (UTC) *::::::::[https://ku.wiktionary.org/w/index.php?title=heval%C3%AA&oldid=6276885 wisa] çawa ye? Bi min nivîsîna nimûneyan zêde ne lazim e ji ber ku ti kes serê xwe pê naêşîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:46, 23 tîrmeh 2026 (UTC) *:::::::::@[[Bikarhêner:Ghybu|Ghybu]] Vê şablonê bi kar bînin an na? Navê şablonê kê çi be? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:07, 24 tîrmeh 2026 (UTC) == Modul:columns == * [[Modul:columns]] were rojanekirin û {{ş|kol3}} bila lînka ''nîşan bide'' deyne beriya sernavê, kolê di qutiya rengî de bila nebe. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Modul:etymon == * [[Modul:etymon kevn]]: Rojanekirin hewce ye. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Javascript = == [[Mediawiki:Gadget-citoid-helper.js]] == Ji bo bi citoidê kopîkirina malûmatên çavkaniyan amûreke wisa lazim e. Xisûsen ji ber ku bi çend amûrên din dikare were bikaranîn. Feqat çend problem hene, şablonên me de kêmasiya parametreyan gelek in û xerîteyên citoidê hîn nehatine çêkirin. Wana sererast bikin dûre vê amûrê çêkin, piştre [[MediaWiki:Gadget-start.js|start.js]] û [[MediaWiki:Gadget-wikt.add-examples.js|add examples.js]] were rojanekirin. - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:04, 19 tîrmeh 2026 (UTC) :Merheba @[[Bikarhêner:Bikarhêner|Bikarhêner]], ez dibêjim karê Modul:quote zêde wext bistîne, bila em dest bi bikaranîna van amûran bikin dûre kêmasiyan em ê temam bikin înşela. Dikarî vana li cihên xwe yên rast kopî paste bikî? # [[Bikarhêner:Wikihez/skrîpt/js/Gadget-citoid-helper.js]] --> [[Mediawiki:Gadget-citoid-helper.js]] # Ya li jêr kopî bike qismê herî dawî ya AmûrênVeşartî li [[MediaWiki:Gadgets-definition]]: ## <code><nowiki>* citoid-helper[ResourceLoader|hidden|default|dependencies=mediawiki.util]|citoid-helper.js</nowiki></code> --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:58, 26 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-start.js]] == Rojanekirin hewce ye. Min gelek tişt lê zêde kir lê ez niha test dikime. Piştre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-start.js]] --> [[MediaWiki:Gadget-start.js]] * [[Bikarhêner:Wikihez/Gadget-start.css]] --> [[MediaWiki:Gadget-start.css]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:08, 17 tîrmeh 2026 (UTC) :Min [[MediaWiki:Gadget-start.js/data.json|data.json]] çêkir ji bo ku bi hêsanî malûmatên heyî werin guhartin bêyî guhartina Javascriptê. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:49, 18 tîrmeh 2026 (UTC) :Xeletiyên ku ji bîr nekim rast bikim: :* Wextê min çavkanî "kitêb" hilbijart û bi destî tije kir xeletiyeke [https://ku.wiktionary.org/w/index.php?title=xezete&diff=prev&oldid=6265392 wisa] derket her kelîme hate lînkkirin. :* <code>html("⠿")</code> ev ne lazim e. :* textarea ji bo çavkaniyên jêgirtinan xaseten yên sernav hîn jî ne draggable e. :* pêşdîtina zindî checkbox wextê tê rakirin, pêşdîtin winda nabe. :* Butona mobîlê ya vekirina formê di moda tarî de belî nabe, tenê wekî qutiyeke tarî xuya dibe. :* Metna hişyarkirinê di guhartina rûpelên heyî de lazim e baştir bikim. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:51, 18 tîrmeh 2026 (UTC) ::Ev problem çêbûn, ez ê binêrim ka çi problemên din hene. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:15, 19 tîrmeh 2026 (UTC) :::Çêke: Ji bo qismê çavkaniyê yek dikare API call û Kategorî:Çavkanî bi kar bîne ji bo ku şablon zêde bikî ji yên heyî. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:21, 19 tîrmeh 2026 (UTC) ::::Ev jî çêbû, min beşa çavkanî jî çêkir. Eger xeletî dernekeve û problema valahiya piştî etîketê ji bîr nekim, piştî rojanekirina amûrên linkify, û citoid em dikarin bar bikin. Ez ê ti tiştê nû îlawe nekim, zêde dirêj bû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:14, 21 tîrmeh 2026 (UTC) == [[Mediawiki:Gadget-QQ.js]] == Ev amûr di şikle Minerva de. Her daîm vê xeletiyê dide: <syntaxhighlight lang="js"> TypeError: Cannot read properties of null (reading 'addEventListener') at css () at runScript () at Array.<anonymous> () at flushCssBuffer () </syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:29, 18 tîrmeh 2026 (UTC) :* [[Bikarhêner:Wikihez/skrîpt/js/Gadget-QQ.js]] --> [[Mediawiki:Gadget-QQ.js]] :* [[Bikarhêner:Wikihez/Gadget-QQ.css]] --> [[Mediawiki:Gadget-QQ.css]] :Ez dibêjim çêbû lê ka çend roj biceribînim. Tiştên ku hatin sererastkirin: :# Google Books API Key dikarî zêde bikî, dixe cookies û di gerokê de dimîne. Berê bê API Key dixebitiya lê êdî mecbûr e ku API Key-a te hebe, bidestxistina wê ne zêde zor e lê dîsa jî tevlihev e. :# Êdî di mobîlê de dixebite, heta di mobîlê de xweştir xuya dike. :# Moda tarî :# OOUI dewsa jquery.ui :# Li qutiyê çi dixwazî zêde bikî, dikare li gorî îsm, sifet, fiîl bitewîne. Lê ji bo fiîl tenê dikare çend heb inflection bîne. :# Butona paqij bike lê zêde kir. :# Çend paqijiyên jêgirtinên Google Kitêbê niha hene. :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:38, 18 tîrmeh 2026 (UTC) ::Tewandina fiîlan û xeletiya modulê lazim e were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:40, 21 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-wikt.add-examples.js]] == Min ev amûr hinek rojane kir feqat çend problem hene berî ku bar bikin. Tiştên ku min guhart: # Êdî li sayfeyên bi {{ş|maneid}} jî dixebite, # Cihê di wîkîtekstê de yê ku jêgirtin were îlawekirin baştir bû, # [[Mediawiki:Gadget-citoid-helper.js|citoid helper]] zêde kir ji bo ku bi hêsanî çavkanî bi riya doi, isbn an urlyê werin tijîkirin. * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.css]] --> [[MediaWiki:Gadget-wikt.add-examples.css]] * [[Bikarhêner:Wikihez/Gadget-wikt.add-examples.js]] --> [[MediaWiki:Gadget-wikt.add-examples.js]] - --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:50, 19 tîrmeh 2026 (UTC) :Min "wikt." qismên cache kirinê ya wîkiya fransî bi [[MediaWiki:Gadget-StorageUtils.js]] guhartiye. loma ji bîr nekin wê amûrê li [[MediaWiki:Gadgets-definition]] zêde bikin. û navê amûrê jî biguhêrînin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:15, 23 tîrmeh 2026 (UTC) == Gadget-translation editor == * [[MediaWiki:Gadget-translation editor.js]]: divê formata en.wîktê were bikaranîn ji ber ku me gelek tercime ji en.wîktê kopî kir û ev js hîn nikare formata wekî li jêr bi kar bîne. <syntaxhighlight lang="wikitext"> * {{Z|sh}}: *: Kirîlî: *: Latînî </syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Gadget-linkify == * [[Mediawiki:Gadget-linkify.js]] ''rûpeleke'' wekî<syntaxhighlight lang="wikitext">[[rûpeleke]]</syntaxhighlight> lînk dike, bi regexê belkî dikare wisa bike <syntaxhighlight lang="wikitext">[[rûpel]]eke</syntaxhighlight> —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) * Amûreke din wekî [[User:Wikihez/Gadget-linkify.js|linkify]] lazim e ku herfên mezin biçûk bike ji bo kurmancî.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Amûra manayê == Amûreke din ji bo nivîsina maneyê wekî Nimûne zêde bike lazim e [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6276876 js] [https://ku.wiktionary.org/w/index.php?title=%C5%9Eablon:ceribandin2&oldid=6265629 şablon] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6265642 css] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:12, 23 tîrmeh 2026 (UTC) == [[MediaWiki:Gadget-jeder.js]] == @[[Bikarhêner:Ghybu|Ghybu]] Çavkaniyên jêderê di moda pêşdîtinê de jêderê vedişêre, ew jî min gelek eciz dike wextê çavkanî zêde dikim. Min ji Claude pirsî û kodan nîşanî wê da, wisa cewab da: Yes — and this file actually explains the whole thing precisely, better than my earlier guess about extract-stripping. What's happening: the CSS rule <syntaxhighlight lang="css"> .jeder{ display:none; } </syntaxhighlight> hides every citation by default, *unconditionally*. The only thing that ever makes it visible again is the gadget's JS: it finds each `.jeder`, builds the short "`— (year, author, +)`" summary from the `.j-pewist` fields, and either reveals the short version or — for citations with no `.j-pewist` fields — explicitly sets `display:inline` on the original. So visibility of citations depends entirely on this JS running. In the normal article view (Image 1) it runs, so you see the collapsed "`(1918, E. Rehmî Ji Mala Hekariyan, Amadekar: M. E. Bozarslan, +)`" form. In whatever generated Image 2 — a hover-preview/extract/API render — gadget JS doesn't execute, so nothing ever removes the `display:none`, and the citation vanishes completely rather than degrading to "still visible, just not collapsed." <b>The fix:</b> flip the default so the *un-collapsed* state is the safe fallback, and let JS do the hiding only after it successfully builds the short version. That way, any context without JS shows the full citation instead of nothing. CSS — remove the blanket hide: <syntaxhighlight lang="css"> .jeder { /* intentionally no display:none here — see Gadget-... .js */ } </syntaxhighlight> JS — do the hiding from script, after the short form exists: <syntaxhighlight lang="js"> // Ji bo şablonên [[Şablon:jêder]] hatiye nivîsandin. // Parametreyên ku di navbera "<span class="j-pewist">...</span>" an "{{j-pêwîst|...}}" de ne venaşêre. $(function() { function nivisaKurtTevliBike(sund, nivisKurt) { var zede = $('<a>+</a>') .addClass('click') .attr('href', '#') .attr('title', 'zêdetir') .css('font-weight', 'bold'); var kurt = $(' <a>↩</a>') .addClass('click-kurt') .attr('href', '#') .attr('title', 'veşêre') .css('font-weight', 'bold'); $('<span>' + nivisKurt + '</span>') .append(zede).append(')') .addClass('jeder-kurt') .css('font-size', '0.85em') .insertAfter(sund); sund.append(' ').append(kurt); // Only hide the full citation once the short summary actually exists. // If this script never runs (no-JS clients, hover-preview extracts, // action=render, etc.), the full citation stays visible instead of // silently disappearing. sund.css('display', 'none'); } function vesere() { $('.jeder').each(function() { var elmTab = $(this).find('.j-pewist').clone(); if (elmTab.length) { var elm = ''; for (var i = elmTab.length - 1; i >= 0; i--) { elm = elmTab.eq(i).html() + ', ' + elm; } var nivisKurt = ' — (' + elm; nivisaKurtTevliBike($(this), nivisKurt); } // else: no j-pewist fields to shorten — leave the full citation // as it already renders (visible), nothing to do. }); } vesere(); $(".click").click(function(e) { e.preventDefault(); $(this).parent('.jeder-kurt').css('display', 'none'); $(this).parent('.jeder-kurt').prev().css('display', 'inline'); }); $(".click-kurt").click(function(e) { e.preventDefault(); $(this).parent('.jeder').css('display', 'none'); $(this).parent('.jeder').next().css('display', 'inline'); }); }); </syntaxhighlight> Net effect: - JS-enabled readers (normal article view): identical experience to today — collapsed short form with `+`/`↩` toggle. - No-JS contexts (previews, extracts, screen readers before JS loads, print, etc.): full citation is shown instead of nothing — a real regression fix rather than a cosmetic one. One caveat worth being upfront about: this fixes it *if* the preview context renders the gadget's HTML/CSS but doesn't execute gadget JS (which is the far more common case, and what this code strongly suggests is happening). If Image 2 instead comes from a pipeline that strips the `.jeder`/`.jegirtin-text` elements out of the HTML entirely before this CSS/JS even gets a chance to apply, no on-wiki CSS/JS change can help — that'd need the extract-generation config changed instead. Given what this gadget file shows, though, I'd bet on the CSS-hide explanation. Em dûre biceribînin eger xeletî tinebe, vî tiştî jî rast bikin. --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:00, 23 tîrmeh 2026 (UTC) :Ez APIya MediaWiki rind nizanim belkî Claude dizane:) Em nikarin bibêjin dema ku moda "''action=edit''" e fonksiyona <code>function vesere()</code> bi kar meyîne. [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 15:57, 24 tîrmeh 2026 (UTC) ::Na, di moda "edît"-ê de <code>var elmTab = null</code>... [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:13, 24 tîrmeh 2026 (UTC) ?: <syntaxhighlight lang="js"> if ( mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') === 'submit' ){ var elmTab = []; } else { var elmTab = $(this).find('.j-pewist').clone(); } </syntaxhighlight> --[[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:31, 24 tîrmeh 2026 (UTC) :Ez jî nizanim Claude çiqas ji mediawiki fêm dike lê heta niha ti tişt nîne ku min jê pirs kir û nikaribû çêke, bila wekî reklam nebe feqat Claude mikemmel e, dibêjim "li vir çima xeletiyeke wisa derdikeve" di dosyeya 2000 rêzî de diçe tiştê xelet tenê rast dike tiştekî din naguherîne. Chatgpt û aistudio qet wisa nakin, eynî dosyeyê deh cara dinivîsin, deh netîceyên cuda derdikevin :D :Em dikarin vê amûrê wextê edit û submitê neaktîv bikin wekî <syntaxhighlight lang="js">if (!(action === "edit" || action === "submit")) { :return;</syntaxhighlight> lê wê demê display:none wê çibe nizanim. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:23, 24 tîrmeh 2026 (UTC) ::display:none ne hewce ye ma jixwe di nav kodê [https://ku.wiktionary.org/w/index.php?title=MediaWiki:Gadget-jeder.js&oldid=6069025#L-49 L-49] de inline/none heye? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:53, 24 tîrmeh 2026 (UTC) :Min bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/vector-2022.js&diff=prev&oldid=6290816#L-28] ceriband feqat nexebitî. "display:none" di pêşdîtinê de dixebite feqat js naşixule. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:43, 25 tîrmeh 2026 (UTC) ::Kodên JSê pir hez nakim (pêşta hukurina APIya MWyê hewce bû) dîsa jî ez ê seh bikim :) [[Bikarhêner:Ghybu|Ghybu]] ([[Gotûbêja bikarhêner:Ghybu|gotûbêj]]) 16:49, 27 tîrmeh 2026 (UTC) :::Ez niha bi vî şiklî [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/test.js&oldid=6290820] [https://ku.wiktionary.org/w/index.php?title=Bikarh%C3%AAner:Wikihez/common.css&oldid=6290821#L-8] bi kar tînim ti problem nîne. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:09, 27 tîrmeh 2026 (UTC) = Moda tarî = == mane? == * {{ş|mane?}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == bêçavkanî == * {{ş|bêçavkanî}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == de-tew-nerm-ern == * {{ş|de-tew-nerm-ern}} —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) = Bot = Karên ku bi botê werin çêkirin ji kerema xwe li vir binivîsin. == Kategorî:Biwêj == [[:Kategorî:Biwêj]] divê were paqijkirin, lîsteya madeyên {{ş|biwêj}} çêke, yên ku tê de bûn, kirin, man hene filtre bike yên din bi destî tê çêkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Jêgirtin == Xistina jêgirtinên beşa [https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%3D+*Ji+%5BWw%5D%C3%AAjey%C3%AA+*%3D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1&searchToken=8rh0bmw8dccsi7aynl6zli8uf ji wêjeyê] li beşa maneyê. —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Bota Toolforgeê == Botekî Toolforgeê lazim e ji bo ku xeletiyên biçûk wekî şablonên bi navên îngilîzî werin kurdîkirin yan jî valahiya beşan rast bike û hwd.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == Updatew == Bota [[Bikarhêner:Wikihez/skrîpt/py/updateW.py|updateW]] divê were rojanekirin. Yan jî yekî nû were çêkirin. Şablonên {{ş|W}} di beşa tercimeyan de sererast dike û zimanan rêz dike. Ya niha xeletiya navê zimanî dide.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) == sihir --> sêhr == Tercimeyên ''[[sêhr]]'' hemû dibêje ''sihir'' loma bi botê lazim e kirin ''sêhr''. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:43, 18 tîrmeh 2026 (UTC) :Sihirbaz --> sêhrbaz [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:07, 18 tîrmeh 2026 (UTC) == Tercimeyên dîroknas == Li tercimeyên [[dîroknas]], hevmaneyên wê hewce ye were îlawekirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:44, 18 tîrmeh 2026 (UTC) == Mewlûd == Sererastkirina jêgirtinên mewlûdê [https://ku.wiktionary.org/w/index.php?search=insource%3A%2Fw%5C%3AMela+His%C3%AAn%C3%AA+Batey%C3%AE%2F&title=Taybet%3AL%C3%AAger%C3%AEn&ns0=1&searchToken=8m0tguy3sqt7edr4sg0u8hedo] wekî [https://ku.wiktionary.org/w/index.php?title=dax%C3%AEdar&curid=284303&diff=6265851&oldid=6142285] [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:43, 20 tîrmeh 2026 (UTC) == [[Modul:ziman/code to canonical name]] == Belgekirina skrîptê û js divê were rastkirin. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:31, 22 tîrmeh 2026 (UTC) :* [[MediaWiki:UpdateLanguageNameAndCode.js]] :[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:50, 22 tîrmeh 2026 (UTC) ::* [[Modul:ziman/print]] ::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:52, 22 tîrmeh 2026 (UTC) :::*[[Modul:ziman/şablon]] :::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 09:56, 22 tîrmeh 2026 (UTC) ::::* [[MediaWiki:Gadget-translation editor.js/ziman.json]] ::::[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 11:06, 22 tîrmeh 2026 (UTC) smfhcsvlhz9cfn50dq6hu796imo4i49 Wîkîferheng:Xebat/arşîv 1 4 1357876 6291783 6276326 2026-07-28T02:18:28Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina nîqaşê ji rûpela [[Wîkîferheng:Xebat]] 6291783 wikitext text/x-wiki == Tercimeyên zel == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6265301#Tercimeyên_zel}} Tercimeyên [[zel]] hatine çêkirin lê "şelmaq" wekî şablon hatiye nivîsîn. Nimûne: "{{g|bg|плесница}}"—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:13, 17 tîrmeh 2026 (UTC) {{arşîv-bin}} == Sererastkirina formata xwestina nimûneyan == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276321#Sererastkirina_formata_xwestina_nimûneyan}} <syntaxhighlight lang="wikitext">#: {{mînak?|ku}}</syntaxhighlight> bike <syntaxhighlight lang="wikitext">#* {{bênimûne|ku}}</syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 01:06, 19 tîrmeh 2026 (UTC) :[https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%5C%23%3A+*%5C%7B%5C%7Bb%3F%C3%AA%3F%28nim%C3%BBne%7Cm%C3%AEnak%29%5C%3F%3F%28%5C%7C%5Ba-z%5D%2B%29%3F%5C%7D%5C%7D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1] Hejmara netîceyan 10.288: [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:37, 20 tîrmeh 2026 (UTC) :Boteke ji bo zêdekirina koda zimanî [https://ku.wiktionary.org/w/index.php?title=Taybet:L%C3%AAger%C3%AEn&limit=20&offset=120&profile=default&search=insource%3A%2Fb%3F%C3%AA%3Fm%C3%AEnak%5C%3F%3F%5C%7D%5C%7D%2F&ns0=1] lazim e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:20, 20 tîrmeh 2026 (UTC) :{{çêbû}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:31, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Gadget-aWa.js == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276324#MediaWiki:Gadget-aWa.js}} Divê were rojanekirin ji bo ku di mobîlê de jî bixebite.[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:59, 17 tîrmeh 2026 (UTC) : Ez dibêjim çêbû lê bila hinekî din test bikim dûre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:04, 17 tîrmeh 2026 (UTC) :Min formata [[WF:Xebat]] wisa kir ku li [[WF:Xebat/arşîv 1]] arşîv bike lê niha dibêjim bila li gotûbêja sayfeyên xwe were zêde kirin wê baştir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:11, 19 tîrmeh 2026 (UTC) ::Lînkek li gotûbêja sayfeya eleqedar were dayîn bes e, wekî din li arşîv 1 were qeydkirin qet nebe dîtina wan hêsantir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:27, 19 tîrmeh 2026 (UTC) :::Ev jî çêbû. {{r|Bikarhêner}} dikarî rûpelên jêr kopî paste bikî? * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:02, 19 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:37, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Newarticletext == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6291781#MediaWiki:Newarticletext}} * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) {{arşîv-bin}} dwvcof9d6qactggdw73sijszw8zojbo 6291785 6291783 2026-07-28T02:24:35Z Wikihez 7344 Restored revision 6276326 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291785 wikitext text/x-wiki == Tercimeyên zel == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6265301#Tercimeyên_zel}} Tercimeyên [[zel]] hatine çêkirin lê "şelmaq" wekî şablon hatiye nivîsîn. Nimûne: "{{g|bg|плесница}}"—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:13, 17 tîrmeh 2026 (UTC) {{arşîv-bin}} == Sererastkirina formata xwestina nimûneyan == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276321#Sererastkirina_formata_xwestina_nimûneyan}} <syntaxhighlight lang="wikitext">#: {{mînak?|ku}}</syntaxhighlight> bike <syntaxhighlight lang="wikitext">#* {{bênimûne|ku}}</syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 01:06, 19 tîrmeh 2026 (UTC) :[https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%5C%23%3A+*%5C%7B%5C%7Bb%3F%C3%AA%3F%28nim%C3%BBne%7Cm%C3%AEnak%29%5C%3F%3F%28%5C%7C%5Ba-z%5D%2B%29%3F%5C%7D%5C%7D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1] Hejmara netîceyan 10.288: [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:37, 20 tîrmeh 2026 (UTC) :Boteke ji bo zêdekirina koda zimanî [https://ku.wiktionary.org/w/index.php?title=Taybet:L%C3%AAger%C3%AEn&limit=20&offset=120&profile=default&search=insource%3A%2Fb%3F%C3%AA%3Fm%C3%AEnak%5C%3F%3F%5C%7D%5C%7D%2F&ns0=1] lazim e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:20, 20 tîrmeh 2026 (UTC) :{{çêbû}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:31, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Gadget-aWa.js == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276324#MediaWiki:Gadget-aWa.js}} Divê were rojanekirin ji bo ku di mobîlê de jî bixebite.[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:59, 17 tîrmeh 2026 (UTC) : Ez dibêjim çêbû lê bila hinekî din test bikim dûre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:04, 17 tîrmeh 2026 (UTC) :Min formata [[WF:Xebat]] wisa kir ku li [[WF:Xebat/arşîv 1]] arşîv bike lê niha dibêjim bila li gotûbêja sayfeyên xwe were zêde kirin wê baştir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:11, 19 tîrmeh 2026 (UTC) ::Lînkek li gotûbêja sayfeya eleqedar were dayîn bes e, wekî din li arşîv 1 were qeydkirin qet nebe dîtina wan hêsantir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:27, 19 tîrmeh 2026 (UTC) :::Ev jî çêbû. {{r|Bikarhêner}} dikarî rûpelên jêr kopî paste bikî? * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:02, 19 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:37, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} 4zccom6szh1djwu53m3xu608h5yoxev 6291788 6291785 2026-07-28T02:25:05Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina nîqaşê ji rûpela [[Wîkîferheng:Xebat]] 6291788 wikitext text/x-wiki == Tercimeyên zel == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6265301#Tercimeyên_zel}} Tercimeyên [[zel]] hatine çêkirin lê "şelmaq" wekî şablon hatiye nivîsîn. Nimûne: "{{g|bg|плесница}}"—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:13, 17 tîrmeh 2026 (UTC) {{arşîv-bin}} == Sererastkirina formata xwestina nimûneyan == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276321#Sererastkirina_formata_xwestina_nimûneyan}} <syntaxhighlight lang="wikitext">#: {{mînak?|ku}}</syntaxhighlight> bike <syntaxhighlight lang="wikitext">#* {{bênimûne|ku}}</syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 01:06, 19 tîrmeh 2026 (UTC) :[https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%5C%23%3A+*%5C%7B%5C%7Bb%3F%C3%AA%3F%28nim%C3%BBne%7Cm%C3%AEnak%29%5C%3F%3F%28%5C%7C%5Ba-z%5D%2B%29%3F%5C%7D%5C%7D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1] Hejmara netîceyan 10.288: [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:37, 20 tîrmeh 2026 (UTC) :Boteke ji bo zêdekirina koda zimanî [https://ku.wiktionary.org/w/index.php?title=Taybet:L%C3%AAger%C3%AEn&limit=20&offset=120&profile=default&search=insource%3A%2Fb%3F%C3%AA%3Fm%C3%AEnak%5C%3F%3F%5C%7D%5C%7D%2F&ns0=1] lazim e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:20, 20 tîrmeh 2026 (UTC) :{{çêbû}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:31, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Gadget-aWa.js == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276324#MediaWiki:Gadget-aWa.js}} Divê were rojanekirin ji bo ku di mobîlê de jî bixebite.[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:59, 17 tîrmeh 2026 (UTC) : Ez dibêjim çêbû lê bila hinekî din test bikim dûre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:04, 17 tîrmeh 2026 (UTC) :Min formata [[WF:Xebat]] wisa kir ku li [[WF:Xebat/arşîv 1]] arşîv bike lê niha dibêjim bila li gotûbêja sayfeyên xwe were zêde kirin wê baştir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:11, 19 tîrmeh 2026 (UTC) ::Lînkek li gotûbêja sayfeya eleqedar were dayîn bes e, wekî din li arşîv 1 were qeydkirin qet nebe dîtina wan hêsantir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:27, 19 tîrmeh 2026 (UTC) :::Ev jî çêbû. {{r|Bikarhêner}} dikarî rûpelên jêr kopî paste bikî? * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:02, 19 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:37, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Newarticletext == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6291786#MediaWiki:Newarticletext}} * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) {{arşîv-bin}} 4c466172u9jcafz6zuss1z5pamwvw8a 6291791 6291788 2026-07-28T02:25:15Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina nîqaşê ji rûpela [[Wîkîferheng:Xebat]] 6291791 wikitext text/x-wiki == Tercimeyên zel == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6265301#Tercimeyên_zel}} Tercimeyên [[zel]] hatine çêkirin lê "şelmaq" wekî şablon hatiye nivîsîn. Nimûne: "{{g|bg|плесница}}"—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 21:13, 17 tîrmeh 2026 (UTC) {{arşîv-bin}} == Sererastkirina formata xwestina nimûneyan == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276321#Sererastkirina_formata_xwestina_nimûneyan}} <syntaxhighlight lang="wikitext">#: {{mînak?|ku}}</syntaxhighlight> bike <syntaxhighlight lang="wikitext">#* {{bênimûne|ku}}</syntaxhighlight> [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 01:06, 19 tîrmeh 2026 (UTC) :[https://ku.wiktionary.org/w/index.php?search=insource%3A%2F%5C%23%3A+*%5C%7B%5C%7Bb%3F%C3%AA%3F%28nim%C3%BBne%7Cm%C3%AEnak%29%5C%3F%3F%28%5C%7C%5Ba-z%5D%2B%29%3F%5C%7D%5C%7D%2F&title=Taybet%3AL%C3%AAger%C3%AEn&profile=advanced&fulltext=1&ns0=1] Hejmara netîceyan 10.288: [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:37, 20 tîrmeh 2026 (UTC) :Boteke ji bo zêdekirina koda zimanî [https://ku.wiktionary.org/w/index.php?title=Taybet:L%C3%AAger%C3%AEn&limit=20&offset=120&profile=default&search=insource%3A%2Fb%3F%C3%AA%3Fm%C3%AEnak%5C%3F%3F%5C%7D%5C%7D%2F&ns0=1] lazim e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 18:20, 20 tîrmeh 2026 (UTC) :{{çêbû}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:31, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Gadget-aWa.js == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6276324#MediaWiki:Gadget-aWa.js}} Divê were rojanekirin ji bo ku di mobîlê de jî bixebite.[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 19:59, 17 tîrmeh 2026 (UTC) : Ez dibêjim çêbû lê bila hinekî din test bikim dûre em bar bikin: * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 22:04, 17 tîrmeh 2026 (UTC) :Min formata [[WF:Xebat]] wisa kir ku li [[WF:Xebat/arşîv 1]] arşîv bike lê niha dibêjim bila li gotûbêja sayfeyên xwe were zêde kirin wê baştir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:11, 19 tîrmeh 2026 (UTC) ::Lînkek li gotûbêja sayfeya eleqedar were dayîn bes e, wekî din li arşîv 1 were qeydkirin qet nebe dîtina wan hêsantir be. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 00:27, 19 tîrmeh 2026 (UTC) :::Ev jî çêbû. {{r|Bikarhêner}} dikarî rûpelên jêr kopî paste bikî? * [[Bikarhêner:Wikihez/Gadget-aWa.css]] --> [[MediaWiki:Gadget-aWa.css]] * [[Bikarhêner:Wikihez/Gadget-aWa.js]] --> [[MediaWiki:Gadget-aWa.js]] --[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 17:02, 19 tîrmeh 2026 (UTC) :{{çêbû}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:37, 21 tîrmeh 2026 (UTC) {{arşîv-bin}} == MediaWiki:Newarticletext == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6291786#MediaWiki:Newarticletext}} * [[MediaWiki:Newarticletext]]: Divê rengên wê were rastkirin.—[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} çavê min kor dikir wextê [[WF:Nû]] rast dikim {{=D}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 20:08, 26 tîrmeh 2026 (UTC) {{arşîv-bin}} == Modul:dara kategoriyan == {{arşîv-ser|xebat|archived|link=Taybet:PermanentLink/6291787#Modul:dara_kategoriyan}} * [[Modul:dara kategoriyan]] link_box —[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:17, 16 tîrmeh 2026 (UTC) *:{{çêbû}} feqat [[Modul:dara kategoriyan/zimankatbike]] çênabe. Claude serê xwar dîsa nebû. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:24, 26 tîrmeh 2026 (UTC) *::ew jî çêbû [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 23:35, 26 tîrmeh 2026 (UTC) {{arşîv-bin}} ql71hfxrmz7zy8ynuz2ef7drlhhcook Bikarhêner:Wikihez/Gadget-start.css 2 1357891 6291631 6291629 2026-07-27T12:16:33Z Wikihez 7344 6291631 css text/css /* =================================================================== MediaWiki:Gadget-start.js — companion styles Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS page). start.js injects no styles at runtime, so this file is the only source of truth for the gadget's appearance — it must be deployed together with start.js. Requires MediaWiki:Gadget-Palette.css to be loaded for the --wikt-palette-* custom properties. Palette.css already re-defines every var for night mode (html.skin-theme-clientpref-night / -os), so rules built from those vars need no dark-mode counterpart here. =================================================================== */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #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; } /* Only reachable on a select that opted out with .wiktku-plain-select — every other select in the form is hidden behind the searchable picker, which carries this width itself (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) Used for EVERY dropdown in the form, desktop and mobile alike -- jquery.chosen is no longer loaded, so there is no .chosen-* CSS here. Structure: span.wiktku-native-select-wrap > input.wiktku-ac-input (the search box) > ul.wiktku-ac-results (the result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* The search box stands in for the native select, so it matches the width the select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Safari/Chrome draw their own clear button and magnifier on input[type=search]; drop them so the box matches every other field. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom and max-height are set inline by showResults(), which flips the list above the box when there is more room up there. The values here are the defaults it starts from. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor (arrow keys); hover mirrors it so mouse and keyboard highlight look the same. :active covers the touch press state on mobile. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, and no hover highlight (it sticks after a tap on touch screens). */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* The insert-a-template pickers keep their tinted backgrounds now that the search box, not the <select>, is what the user actually sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input { background: var(--wikt-palette-amber-1); font-size: 0.9em; } .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { background: var(--wikt-palette-cyan-3); font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows (Ziman, Dûnde, Werger, Zarava) — the picker has to line up with the word fields sitting next to it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-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-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } .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-pron-wrap, .wiktku-etym-wrap { display: flex; flex-direction: column; gap: 4px; } .wiktku-pron-wrap textarea.wiktku-pron-text { background: var(--wikt-palette-amber-0); } .wiktku-etym-wrap textarea.wiktku-etym-text { background: var(--wikt-palette-cyan-3); } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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) / Bi zaravayên din (dialect) groups — one per gloss; the two sections share identical spacing and label styling. ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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; } /* One column, so let the search box and its list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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 .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode MediaWiki:Gadget-Palette.css already re-defines every --wikt-palette-* var for night mode, on html.skin-theme-clientpref-night and (for the "follow OS" setting) html.skin-theme-clientpref-os under a dark OS preference. So any rule above that is built from those vars flips by itself and needs nothing here. What used to live here was a bare @media (prefers-color-scheme: dark) block. That was the wrong hook twice over: it fired even when the reader had explicitly chosen light mode on-wiki, and almost every rule in it just restated the light rule with the same var. The only genuine exceptions were the .chosen-* overrides, and jquery.chosen is no longer loaded at all. Keep this hook for anything that has to be a real colour rather than a palette var — here, only the panel's edge, because a drop shadow does nothing against an equally dark page. The two selectors below mirror Palette.css exactly. Note what is deliberately NOT here: li:active sets `color: var(--wikt-palette-white)`, and that var flips to #101418 at night, so the pressed row is dark-on-light in night mode all by itself (9.3:1). Re-stating that colour here as --wikt-palette-black would make it light-on-light and drop it to 1.7:1. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Lift the panel off an equally dark page: the light-mode drop shadow is invisible on a dark background, so lean on the border instead. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* ── "Zimanek lê zêde bike" portlet link icon (Minerva/mobile) ── */ /* Minerva auto-generates the icon span class from the portlet link id. */ /* Uses Feather-core-edit.svg from Wikimedia Commons via CSS mask, matching */ /* the exact pattern Minerva uses for all its own icons. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } rcl9et9qvlrfiqj4cv7j92vah3awfzo 6291634 6291631 2026-07-27T12:24:01Z Wikihez 7344 6291634 css text/css /* =================================================================== MediaWiki:Gadget-start.js — companion styles Copy this file into MediaWiki:Common.css (or a dedicated gadget CSS page). start.js injects no styles at runtime, so this file is the only source of truth for the gadget's appearance — it must be deployed together with start.js. Requires MediaWiki:Gadget-Palette.css to be loaded for the --wikt-palette-* custom properties. Palette.css already re-defines every var for night mode (html.skin-theme-clientpref-night / -os), so rules built from those vars need no dark-mode counterpart here. =================================================================== */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #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; } /* Only reachable on a select that opted out with .wiktku-plain-select — every other select in the form is hidden behind the searchable picker, which carries this width itself (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) Used for EVERY dropdown in the form, desktop and mobile alike -- jquery.chosen is no longer loaded, so there is no .chosen-* CSS here. Structure: span.wiktku-native-select-wrap > input.wiktku-ac-input (the search box) > ul.wiktku-ac-results (the result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* The search box stands in for the native select, so it matches the width the select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Safari/Chrome draw their own clear button and magnifier on input[type=search]; drop them so the box matches every other field. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom and max-height are set inline by showResults(), which flips the list above the box when there is more room up there. The values here are the defaults it starts from. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor (arrow keys); hover mirrors it so mouse and keyboard highlight look the same. :active covers the touch press state on mobile. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, and no hover highlight (it sticks after a tap on touch screens). */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* The insert-a-template pickers stretch to fill their container now that the search box, not the <select>, is what the user actually sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows (Ziman, Dûnde, Werger, Zarava) — the picker has to line up with the word fields sitting next to it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-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-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } .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; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 4px; } .wiktku-pron-wrap, .wiktku-etym-wrap { display: flex; flex-direction: column; gap: 4px; } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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) / Bi zaravayên din (dialect) groups — one per gloss; the two sections share identical spacing and label styling. ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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; } /* One column, so let the search box and its list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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 .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode MediaWiki:Gadget-Palette.css already re-defines every --wikt-palette-* var for night mode, on html.skin-theme-clientpref-night and (for the "follow OS" setting) html.skin-theme-clientpref-os under a dark OS preference. So any rule above that is built from those vars flips by itself and needs nothing here. What used to live here was a bare @media (prefers-color-scheme: dark) block. That was the wrong hook twice over: it fired even when the reader had explicitly chosen light mode on-wiki, and almost every rule in it just restated the light rule with the same var. The only genuine exceptions were the .chosen-* overrides, and jquery.chosen is no longer loaded at all. Keep this hook for anything that has to be a real colour rather than a palette var — here, only the panel's edge, because a drop shadow does nothing against an equally dark page. The two selectors below mirror Palette.css exactly. Note what is deliberately NOT here: li:active sets `color: var(--wikt-palette-white)`, and that var flips to #101418 at night, so the pressed row is dark-on-light in night mode all by itself (9.3:1). Re-stating that colour here as --wikt-palette-black would make it light-on-light and drop it to 1.7:1. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Lift the panel off an equally dark page: the light-mode drop shadow is invisible on a dark background, so lean on the border instead. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* ── "Zimanek lê zêde bike" portlet link icon (Minerva/mobile) ── */ /* Minerva auto-generates the icon span class from the portlet link id. */ /* Uses Feather-core-edit.svg from Wikimedia Commons via CSS mask, matching */ /* the exact pattern Minerva uses for all its own icons. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } 7khpqr5ihnygscvs251ndkppgee9z3x 6291646 6291634 2026-07-27T13:17:39Z Wikihez 7344 6291646 css text/css /* =================================================================== Requires MediaWiki:Gadget-Palette.css to be loaded for the --wikt-palette-* custom properties. =================================================================== */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #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; } /* Only reachable on a select that opted out with .wiktku-plain-select — every other select in the form is hidden behind the searchable picker, which carries this width itself (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) Structure: span.wiktku-native-select-wrap > input.wiktku-ac-input (the search box) > ul.wiktku-ac-results (the result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* The search box stands in for the native select, so it matches the width the select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Safari/Chrome draw their own clear button and magnifier on input[type=search]; drop them so the box matches every other field. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom and max-height are set inline by showResults(), which flips the list above the box when there is more room up there. The values here are the defaults it starts from. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor (arrow keys); hover mirrors it so mouse and keyboard highlight look the same. :active covers the touch press state on mobile. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, and no hover highlight (it sticks after a tap on touch screens). */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* The insert-a-template pickers stretch to fill their container now that the search box, not the <select>, is what the user actually sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows (Ziman, Dûnde, Werger, Zarava) — the picker has to line up with the word fields sitting next to it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-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-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } .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; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 4px; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 4px; } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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) / Zarava rows: the lang picker box and the first word textarea sit side by side and should line up at the same height. The textarea is height: calc(1em + 8px) with box-sizing: border-box (see the shared textarea.wiktku-start-narrow rule above), so give the picker's search box the exact same box-sizing/height/vertical padding. */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 8px); min-height: calc(1em + 8px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger (translation) / Bi zaravayên din (dialect) groups — one per gloss; the two sections share identical spacing and label styling. ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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; } /* One column, so let the search box and its list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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 .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode MediaWiki:Gadget-Palette.css already re-defines every --wikt-palette-* var for night mode, on html.skin-theme-clientpref-night and (for the "follow OS" setting) html.skin-theme-clientpref-os under a dark OS preference. So any rule above that is built from those vars flips by itself and needs nothing here. What used to live here was a bare @media (prefers-color-scheme: dark) block. That was the wrong hook twice over: it fired even when the reader had explicitly chosen light mode on-wiki, and almost every rule in it just restated the light rule with the same var. The only genuine exceptions were the .chosen-* overrides, and jquery.chosen is no longer loaded at all. Keep this hook for anything that has to be a real colour rather than a palette var — here, only the panel's edge, because a drop shadow does nothing against an equally dark page. The two selectors below mirror Palette.css exactly. Note what is deliberately NOT here: li:active sets `color: var(--wikt-palette-white)`, and that var flips to #101418 at night, so the pressed row is dark-on-light in night mode all by itself (9.3:1). Re-stating that colour here as --wikt-palette-black would make it light-on-light and drop it to 1.7:1. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Lift the panel off an equally dark page: the light-mode drop shadow is invisible on a dark background, so lean on the border instead. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* ── "Zimanek lê zêde bike" portlet link icon (Minerva/mobile) ── */ /* Minerva auto-generates the icon span class from the portlet link id. */ /* Uses Feather-core-edit.svg from Wikimedia Commons via CSS mask, matching */ /* the exact pattern Minerva uses for all its own icons. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } b5wgd3we82xc6ecfn900u1o3g6nhlmh 6291678 6291646 2026-07-27T18:13:57Z Wikihez 7344 6291678 css text/css /* =================================================================== Requires MediaWiki:Gadget-Palette.css to be loaded for the --wikt-palette-* custom properties. =================================================================== */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #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; } /* Only reachable on a select that opted out with .wiktku-plain-select — every other select in the form is hidden behind the searchable picker, which carries this width itself (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) Structure: span.wiktku-native-select-wrap > input.wiktku-ac-input (the search box) > ul.wiktku-ac-results (the result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* The search box stands in for the native select, so it matches the width the select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Safari/Chrome draw their own clear button and magnifier on input[type=search]; drop them so the box matches every other field. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom and max-height are set inline by showResults(), which flips the list above the box when there is more room up there. The values here are the defaults it starts from. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor (arrow keys); hover mirrors it so mouse and keyboard highlight look the same. :active covers the touch press state on mobile. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, and no hover highlight (it sticks after a tap on touch screens). */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* The insert-a-template pickers stretch to fill their container now that the search box, not the <select>, is what the user actually sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows (Ziman, Dûnde, Werger, Zarava) — the picker has to line up with the word fields sitting next to it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --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-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 4px; } .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; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 4px; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 4px; } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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) / Zarava rows: the lang picker box and the first word textarea sit side by side and should line up at the same height. The textarea is height: calc(1em + 8px) with box-sizing: border-box (see the shared textarea.wiktku-start-narrow rule above), so give the picker's search box the exact same box-sizing/height/vertical padding. */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 8px); min-height: calc(1em + 8px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger (translation) / Bi zaravayên din (dialect) groups — one per gloss; the two sections share identical spacing and label styling. ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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; } /* One column, so let the search box and its list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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 .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode MediaWiki:Gadget-Palette.css already re-defines every --wikt-palette-* var for night mode, on html.skin-theme-clientpref-night and (for the "follow OS" setting) html.skin-theme-clientpref-os under a dark OS preference. So any rule above that is built from those vars flips by itself and needs nothing here. What used to live here was a bare @media (prefers-color-scheme: dark) block. That was the wrong hook twice over: it fired even when the reader had explicitly chosen light mode on-wiki, and almost every rule in it just restated the light rule with the same var. The only genuine exceptions were the .chosen-* overrides, and jquery.chosen is no longer loaded at all. Keep this hook for anything that has to be a real colour rather than a palette var — here, only the panel's edge, because a drop shadow does nothing against an equally dark page. The two selectors below mirror Palette.css exactly. Note what is deliberately NOT here: li:active sets `color: var(--wikt-palette-white)`, and that var flips to #101418 at night, so the pressed row is dark-on-light in night mode all by itself (9.3:1). Re-stating that colour here as --wikt-palette-black would make it light-on-light and drop it to 1.7:1. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Lift the panel off an equally dark page: the light-mode drop shadow is invisible on a dark background, so lean on the border instead. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* ── "Zimanek lê zêde bike" portlet link icon (Minerva/mobile) ── */ /* Minerva auto-generates the icon span class from the portlet link id. */ /* Uses Feather-core-edit.svg from Wikimedia Commons via CSS mask, matching */ /* the exact pattern Minerva uses for all its own icons. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } i3xprkug2oucc9g6j47yi6cj067pvbx 6291693 6291678 2026-07-27T20:01:20Z Wikihez 7344 6291693 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #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; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --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-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 4px; } .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; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 4px; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 4px; } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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/Zarava rows: align the picker's height with the adjacent word textarea (height: calc(1em + 8px), see .wiktku-start-narrow above). */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 8px); min-height: calc(1em + 8px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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; } /* Single column: search box and list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } gc9nmryei6llfxqq3hcadlf0arodfyx 6291699 6291693 2026-07-27T20:21:09Z Wikihez 7344 6291699 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #e0e0e0); } /* =================================================================== Compact layout — steps grouped side by side instead of each getting its own full-width block (see STEP_ROW_GROUPS / .compact in start.js). Each grouped/compact step keeps its own #wiktku-start-<id> div and behavior; only its container and spacing change. =================================================================== */ .wiktku-start-step-row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 1.5em; padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #e0e0e0); } .wiktku-start-step-row .wiktku-start-step-grouped { padding: 0; border-bottom: none; } /* Ziman + Bilêvkirin: two columns instead of two stacked full steps. */ .wiktku-row-lang-pron .wiktku-start-step-grouped { flex: 1 1 260px; min-width: 220px; } .wiktku-row-lang-pron .wiktku-start-step-grouped .wiktku-native-select-wrap, .wiktku-row-lang-pron .wiktku-start-step-grouped input.wiktku-ac-input { width: 100%; } /* Cureyê rêzimanî keeps its full look; cinsiyet/lektur/tr ride along next to it as tiny boxes instead of each being its own full step. */ .wiktku-row-pos-extras #wiktku-start-pos { flex: 1 1 260px; min-width: 220px; } .wiktku-row-pos-extras #wiktku-start-cinsiyet, .wiktku-row-pos-extras #wiktku-start-lektur, .wiktku-row-pos-extras #wiktku-start-tr { flex: 0 0 auto; max-width: 12em; } .wiktku-row-pos-extras #wiktku-start-cinsiyet .wiktku-start-step-name, .wiktku-row-pos-extras #wiktku-start-lektur .wiktku-start-step-name, .wiktku-row-pos-extras #wiktku-start-tr .wiktku-start-step-name { display: none; } .wiktku-row-pos-extras #wiktku-start-cinsiyet .wiktku-start-step-question, .wiktku-row-pos-extras #wiktku-start-lektur .wiktku-start-step-question, .wiktku-row-pos-extras #wiktku-start-tr .wiktku-start-step-question { display: block; font-size: 85%; padding-right: 0; margin-bottom: 2px; } .wiktku-row-pos-extras #wiktku-start-cinsiyet select.wiktku-start-step-field, .wiktku-row-pos-extras #wiktku-start-lektur .wiktku-native-select-wrap, .wiktku-row-pos-extras #wiktku-start-lektur input.wiktku-ac-input, .wiktku-row-pos-extras #wiktku-start-tr textarea.wiktku-start-step-field { width: 10em; max-width: 10em; } /* Jê / Têkildar / Binêre herwiha: same growing word list, far less heading weight and padding than a full step. */ .wiktku-start-step-compact { padding: 0.5em 0; } .wiktku-start-step-compact .wiktku-start-step-name { font-size: 100%; margin: 0 0 2px; } .wiktku-start-step-compact .wiktku-start-step-question { font-size: 95%; } .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; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --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-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 4px; } .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; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 4px; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 4px; } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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/Zarava rows: align the picker's height with the adjacent word textarea (height: calc(1em + 8px), see .wiktku-start-narrow above). */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 8px); min-height: calc(1em + 8px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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, .wiktku-start-step-row { flex-direction: column; } .wiktku-start-step-row .wiktku-start-step-grouped { flex: 1 1 auto; width: 100%; } .wiktku-row-pos-extras #wiktku-start-cinsiyet, .wiktku-row-pos-extras #wiktku-start-lektur, .wiktku-row-pos-extras #wiktku-start-tr { max-width: 100%; } .wiktku-row-pos-extras #wiktku-start-cinsiyet select.wiktku-start-step-field, .wiktku-row-pos-extras #wiktku-start-lektur input.wiktku-ac-input, .wiktku-row-pos-extras #wiktku-start-tr textarea.wiktku-start-step-field { width: 100%; max-width: 100%; } /* Single column: search box and list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } 1t1mpuns9ydoaryppvxzf0br30rt3yn 6291704 6291699 2026-07-27T20:25:01Z Wikihez 7344 Restored revision 6291693 by [[Special:Contributions/Wikihez|Wikihez]] ([[User talk:Wikihez|talk]]) ([[:m:User:Xiplus/TwinkleGlobal|TwinkleGlobal]]) 6291704 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); } .wiktku-start-step { padding: 1em 0; border-bottom: 1px solid var(--wikt-palette-grey-3, #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; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em; } #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; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 14em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } ul.wiktku-ac-results li { margin: 0; padding: 5px 8px; cursor: pointer; font-size: 0.95em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.4em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.4em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.9em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── 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; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --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-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 4px; } .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; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 4px; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 4px; } /* ── POS section tabs ── */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #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/Zarava rows: align the picker's height with the adjacent word textarea (height: calc(1em + 8px), see .wiktku-start-narrow above). */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 8px); min-height: calc(1em + 8px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.8em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: bold; font-size: 0.9em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 4px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.2em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 2em; } .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-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 4px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.85em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .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; } /* Single column: search box and list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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 textarea.wiktku-cavkani-text { --wiktku-ta-rows: 6; 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, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.4em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } gc9nmryei6llfxqq3hcadlf0arodfyx 6291712 6291704 2026-07-27T20:40:50Z Wikihez 7344 6291712 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ /* =================================================================== Base scale Everything under the form is scaled down a notch and given a tighter line-height. This is the single biggest lever on "too much scrolling": at 100% + default line-height, ~30 form steps easily doubles the page height compared to 92% + 1.35 line-height. =================================================================== */ #wiktku-start-form, #wiktku-preview-container { font-size: 0.92em; line-height: 1.35; } #wiktku-start-form * , #wiktku-preview-container * { box-sizing: border-box; } .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 4px; } /* =================================================================== Step cards Was: padding: 1em 0 + border-bottom (a flat divider list). Now: a compact card with a left accent bar, so each step reads as a distinct unit without needing a full em of air above and below it. =================================================================== */ .wiktku-start-step { padding: 0.55em 0.7em; margin-bottom: 0.4em; border: 1px solid var(--wikt-palette-grey-3, #e0e0e0); border-left: 3px solid var(--wikt-palette-blue-9, #3366cc); border-radius: 3px; background: var(--wikt-palette-white); transition: border-left-color 0.15s ease; } .wiktku-start-step:focus-within { border-left-color: var(--wikt-palette-blue-9, #3366cc); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); } .wiktku-start-step-question { font-size: 104%; font-weight: 600; margin: 0 0 0.35em; line-height: 1.3; } .wiktku-start-step label { padding-right: 1.2em; font-size: 0.95em; } input[type="text"].wiktku-start-step-field { width: 100%; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } input[type="text"].wiktku-start-step-field.wiktku-start-narrow { width: 20em; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; padding: 0.6em 0.2em; position: sticky; bottom: 0; background: var(--wikt-palette-white); border-top: 1px solid var(--wikt-palette-grey-3, #e0e0e0); z-index: 5; } #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; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } #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 + 6px); min-height: calc(1em + 6px); padding-top: 2px !important; padding-bottom: 2px !important; line-height: 1.35 !important; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 3px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; transition: border-color 0.1s ease, box-shadow 0.1s ease; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 13em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15); } ul.wiktku-ac-results li { margin: 0; padding: 4px 8px; cursor: pointer; font-size: 0.92em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.2em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.2em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── Wikitext preview panel ── */ #wiktku-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; white-space: pre-wrap; word-break: break-word; font-family: monospace; font-size: 0.85em; } /* ── Live rendered preview panel (desktop only) ── */ #wiktku-live-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; word-break: break-word; min-height: 2em; } /* ── Preview container (holds wikitext + live panels) ── */ #wiktku-preview-container { display: flex; flex-wrap: wrap; gap: 0.8em; margin-top: 0.4em; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --wiktku-ta-rows: 2; width: 100%; box-sizing: border-box; height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); min-height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); } #wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text, #wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text, #wiktku-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 3px; } .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.35 !important; font-size: 0.88em; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 3px; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 3px; } /* ── POS section tabs ── Modernized into rounded pills instead of flat file-folder tabs. */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #wiktku-section-tabs .wiktku-section-tab { padding: 3px 12px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 999px; background: var(--wikt-palette-dullcyan); cursor: pointer; font-size: 0.86em; user-select: none; transition: background 0.12s ease, border-color 0.12s ease; } #wiktku-section-tabs .wiktku-section-tab:hover { border-color: var(--wikt-palette-blue-9, #3366cc); } #wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active { background: var(--wikt-palette-blue-9, #3366cc); border-color: var(--wikt-palette-blue-9, #3366cc); color: var(--wikt-palette-white); font-weight: 600; } .wiktku-lang-row-list { margin: 0; padding: 0; list-style: none; } .wiktku-lang-row { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 3px; flex-wrap: wrap; } .wiktku-lang-row-words { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; } /* Werger/Zarava rows: align the picker's height with the adjacent word textarea (height: calc(1em + 6px), see .wiktku-start-narrow above). */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 6px); min-height: calc(1em + 6px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.6em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: 600; font-size: 0.88em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 3px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.15em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 1.8em; } .wiktku-dfn-quote-src-sel { font-size: 0.88em; margin-top: 3px; display: block; } .wiktku-dfn-quote-src-fields { display: flex; flex-direction: column; gap: 3px; margin-top: 3px; } .wiktku-dfn-quote-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 3px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.82em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .wiktku-dfn-quote-src-row { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; } .wiktku-dfn-quote-src-row label { font-size: 0.82em; 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; } /* Single column: search box and list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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: 3; font-size: 1em; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 5; 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: 2; font-size: 1em; } .wiktku-dfn-nimune-sub, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.2em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } .wiktku-start-step { padding: 0.5em 0.6em; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } html.skin-theme-clientpref-night .wiktku-start-step { box-shadow: none; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } 004egpt0sglcb0b3dumftb877ze7g25 6291714 6291712 2026-07-27T20:53:09Z Wikihez 7344 6291714 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ /* =================================================================== Base scale Everything under the form is scaled down a notch and given a tighter line-height. This is the single biggest lever on "too much scrolling": at 100% + default line-height, ~30 form steps easily doubles the page height compared to 92% + 1.35 line-height. =================================================================== */ #wiktku-start-form, #wiktku-preview-container { font-size: 0.92em; line-height: 1.35; } #wiktku-start-form * , #wiktku-preview-container * { box-sizing: border-box; } .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 4px; } /* =================================================================== Step cards Was: padding: 1em 0 + border-bottom (a flat divider list). Now: a compact card with a left accent bar, so each step reads as a distinct unit without needing a full em of air above and below it. =================================================================== */ .wiktku-start-step { padding: 0.55em 0.7em; margin-bottom: 0.4em; border: 1px solid var(--wikt-palette-grey-3, #e0e0e0); border-left: 3px solid var(--wikt-palette-blue-9, #3366cc); border-radius: 3px; background: var(--wikt-palette-white); transition: border-left-color 0.15s ease; } .wiktku-start-step:focus-within { border-left-color: var(--wikt-palette-blue-9, #3366cc); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); } .wiktku-start-step-question { font-size: 104%; font-weight: 600; margin: 0 0 0.35em; line-height: 1.3; } .wiktku-start-step label { padding-right: 1.2em; font-size: 0.95em; } input[type="text"].wiktku-start-step-field { width: 100%; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } input[type="text"].wiktku-start-step-field.wiktku-start-narrow { width: 20em; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; padding: 0.6em 0.2em; position: sticky; bottom: 0; background: var(--wikt-palette-white); border-top: 1px solid var(--wikt-palette-grey-3, #e0e0e0); z-index: 5; } #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; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } #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 + 6px); min-height: calc(1em + 6px); padding-top: 2px !important; padding-bottom: 2px !important; line-height: 1.35 !important; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 3px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; transition: border-color 0.1s ease, box-shadow 0.1s ease; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 13em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15); } ul.wiktku-ac-results li { margin: 0; padding: 4px 8px; cursor: pointer; font-size: 0.92em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.2em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.2em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── Wikitext preview panel ── */ #wiktku-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; white-space: pre-wrap; word-break: break-word; font-family: monospace; font-size: 0.85em; } /* ── Live rendered preview panel (desktop only) ── */ #wiktku-live-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; word-break: break-word; min-height: 2em; } /* ── Preview container (holds wikitext + live panels) ── */ #wiktku-preview-container { display: flex; flex-wrap: wrap; gap: 0.8em; margin-top: 0.4em; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --wiktku-ta-rows: 2; width: 100%; box-sizing: border-box; height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); min-height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); } #wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text, #wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text, #wiktku-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 3px; } .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.35 !important; font-size: 0.88em; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 3px; } /* ── Sub-field titles (Etîket, Kategorî, Hevmane, Dijmane, Nimûne, Jêgirtin, …) — previously plain unstyled run-on text. Each group now reads as a small labelled field: the term stands out, the izah hint stays quiet, and the block gets its own breathing room. ── */ .wiktku-dfn-subgroup { margin-top: 0.5em; padding-top: 0.4em; border-top: 1px dashed var(--wikt-palette-grey-3, #e0e0e0); } .wiktku-dfn-subgroup:first-of-type { margin-top: 0.3em; padding-top: 0; border-top: none; } .wiktku-dfn-sublabel { display: block; margin-bottom: 3px; font-size: 0.88em; } .wiktku-dfn-sublabel-term { font-weight: 600; color: var(--wikt-palette-blue-9, #3366cc); text-transform: uppercase; letter-spacing: 0.03em; font-size: 0.92em; } .wiktku-dfn-sublabel-hint { color: var(--wikt-palette-grey-9, #767676); font-style: italic; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 3px; } /* ── POS section tabs ── Modernized into rounded pills instead of flat file-folder tabs. */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #wiktku-section-tabs .wiktku-section-tab { padding: 3px 12px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 999px; background: var(--wikt-palette-dullcyan); cursor: pointer; font-size: 0.86em; user-select: none; transition: background 0.12s ease, border-color 0.12s ease; } #wiktku-section-tabs .wiktku-section-tab:hover { border-color: var(--wikt-palette-blue-9, #3366cc); } #wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active { background: var(--wikt-palette-blue-9, #3366cc); border-color: var(--wikt-palette-blue-9, #3366cc); color: var(--wikt-palette-white); font-weight: 600; } .wiktku-lang-row-list { margin: 0; padding: 0; list-style: none; } .wiktku-lang-row { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 3px; flex-wrap: wrap; } .wiktku-lang-row-words { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; } /* Werger/Zarava rows: align the picker's height with the adjacent word textarea (height: calc(1em + 6px), see .wiktku-start-narrow above). */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 6px); min-height: calc(1em + 6px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.6em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: 600; font-size: 0.88em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 3px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.15em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 1.8em; } .wiktku-dfn-quote-src-sel { font-size: 0.88em; margin-top: 3px; display: block; } .wiktku-dfn-quote-src-fields { display: flex; flex-direction: column; gap: 3px; margin-top: 3px; } .wiktku-dfn-quote-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 3px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.82em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .wiktku-dfn-quote-src-row { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; } .wiktku-dfn-quote-src-row label { font-size: 0.82em; 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; } /* Single column: search box and list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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: 3; font-size: 1em; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 5; 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: 2; font-size: 1em; } .wiktku-dfn-nimune-sub, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.2em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } .wiktku-start-step { padding: 0.5em 0.6em; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } html.skin-theme-clientpref-night .wiktku-start-step { box-shadow: none; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } 93gvklxey5d47p35gtl2oq4gisp77b5 6291716 6291714 2026-07-27T21:03:25Z Wikihez 7344 6291716 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ /* =================================================================== Base scale Everything under the form is scaled down a notch and given a tighter line-height. This is the single biggest lever on "too much scrolling": at 100% + default line-height, ~30 form steps easily doubles the page height compared to 92% + 1.35 line-height. =================================================================== */ #wiktku-start-form, #wiktku-preview-container { font-size: 0.92em; line-height: 1.35; } #wiktku-start-form * , #wiktku-preview-container * { box-sizing: border-box; } .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 4px; } /* =================================================================== Step cards Was: padding: 1em 0 + border-bottom (a flat divider list). Now: a compact card with a left accent bar, so each step reads as a distinct unit without needing a full em of air above and below it. =================================================================== */ .wiktku-start-step { padding: 0.55em 0.7em; margin-bottom: 0.4em; border: 1px solid var(--wikt-palette-grey-3, #e0e0e0); border-left: 3px solid var(--wikt-palette-blue-9, #3366cc); border-radius: 3px; background: var(--wikt-palette-white); transition: border-left-color 0.15s ease; } .wiktku-start-step:focus-within { border-left-color: var(--wikt-palette-blue-9, #3366cc); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); } .wiktku-start-step-question { font-size: 104%; font-weight: 600; margin: 0 0 0.35em; line-height: 1.3; } .wiktku-start-step label { padding-right: 1.2em; font-size: 0.95em; } input[type="text"].wiktku-start-step-field { width: 100%; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } input[type="text"].wiktku-start-step-field.wiktku-start-narrow { width: 20em; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; padding: 0.6em 0.2em; position: sticky; bottom: 0; background: var(--wikt-palette-white); border-top: 1px solid var(--wikt-palette-grey-3, #e0e0e0); z-index: 5; } /* ── "Bişîne" click feedback ── A toast alone is easy to miss, and the disabled/spinner state only appears once getWikitext resolves. This gives an instant, unmissable confirmation the click registered, right at the point of contact. */ @keyframes wiktku-btn-flash-pulse { 0% { box-shadow: 0 0 0 0 rgba(51, 102, 204, 0.55); } 70% { box-shadow: 0 0 0 9px rgba(51, 102, 204, 0); } 100% { box-shadow: 0 0 0 0 rgba(51, 102, 204, 0); } } #wiktku-unhide-editform.wiktku-btn-flash { animation: wiktku-btn-flash-pulse 0.5s ease-out; } /* Persistent state while the wikitext is being built/submitted, set alongside OOUI's own setDisabled(true) so it reads clearly even if the skin's default disabled style is subtle. */ #wiktku-unhide-editform.wiktku-btn-sending .oo-ui-buttonElement-button { background-color: var(--wikt-palette-grey-9, #767676) !important; border-color: var(--wikt-palette-grey-9, #767676) !important; cursor: progress; opacity: 1 !important; } #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; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } #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 + 6px); min-height: calc(1em + 6px); padding-top: 2px !important; padding-bottom: 2px !important; line-height: 1.35 !important; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 3px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; transition: border-color 0.1s ease, box-shadow 0.1s ease; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 13em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15); } ul.wiktku-ac-results li { margin: 0; padding: 4px 8px; cursor: pointer; font-size: 0.92em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.2em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.2em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── Wikitext preview panel ── */ #wiktku-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; white-space: pre-wrap; word-break: break-word; font-family: monospace; font-size: 0.85em; } /* ── Live rendered preview panel (desktop only) ── */ #wiktku-live-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; word-break: break-word; min-height: 2em; } /* ── Preview container (holds wikitext + live panels) ── */ #wiktku-preview-container { display: flex; flex-wrap: wrap; gap: 0.8em; margin-top: 0.4em; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --wiktku-ta-rows: 2; width: 100%; box-sizing: border-box; height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); min-height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); } #wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text, #wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text, #wiktku-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 3px; } .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.35 !important; font-size: 0.88em; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 3px; } /* ── Sub-field titles (Etîket, Kategorî, Hevmane, Dijmane, Nimûne, Jêgirtin, …) — previously plain unstyled run-on text. Each group now reads as a small labelled field: the term stands out, the izah hint stays quiet, and the block gets its own breathing room. ── */ .wiktku-dfn-subgroup { margin-top: 0.5em; padding-top: 0.4em; border-top: 1px dashed var(--wikt-palette-grey-3, #e0e0e0); } .wiktku-dfn-subgroup:first-of-type { margin-top: 0.3em; padding-top: 0; border-top: none; } .wiktku-dfn-sublabel { display: block; margin-bottom: 3px; font-size: 0.88em; } .wiktku-dfn-sublabel-term { font-weight: 600; color: var(--wikt-palette-blue-9, #3366cc); text-transform: uppercase; letter-spacing: 0.03em; font-size: 0.92em; } .wiktku-dfn-sublabel-hint { color: var(--wikt-palette-grey-9, #767676); font-style: italic; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 3px; } /* ── POS section tabs ── Modernized into rounded pills instead of flat file-folder tabs. */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #wiktku-section-tabs .wiktku-section-tab { padding: 3px 12px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 999px; background: var(--wikt-palette-dullcyan); cursor: pointer; font-size: 0.86em; user-select: none; transition: background 0.12s ease, border-color 0.12s ease; } #wiktku-section-tabs .wiktku-section-tab:hover { border-color: var(--wikt-palette-blue-9, #3366cc); } #wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active { background: var(--wikt-palette-blue-9, #3366cc); border-color: var(--wikt-palette-blue-9, #3366cc); color: var(--wikt-palette-white); font-weight: 600; } .wiktku-lang-row-list { margin: 0; padding: 0; list-style: none; } .wiktku-lang-row { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 3px; flex-wrap: wrap; } .wiktku-lang-row-words { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; } /* Werger/Zarava rows: align the picker's height with the adjacent word textarea (height: calc(1em + 6px), see .wiktku-start-narrow above). */ .wiktku-trans-row .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-zarava-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1em + 6px); min-height: calc(1em + 6px); padding-top: 2px; padding-bottom: 2px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.6em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: 600; font-size: 0.88em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 3px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.15em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 1.8em; } .wiktku-dfn-quote-src-sel { font-size: 0.88em; margin-top: 3px; display: block; } .wiktku-dfn-quote-src-fields { display: flex; flex-direction: column; gap: 3px; margin-top: 3px; } .wiktku-dfn-quote-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 3px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.82em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .wiktku-dfn-quote-src-row { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; } .wiktku-dfn-quote-src-row label { font-size: 0.82em; 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; } /* Single column: search box and list use the full width. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results { width: 100%; max-width: 100%; } #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: 3; font-size: 1em; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 5; 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: 2; font-size: 1em; } .wiktku-dfn-nimune-sub, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.2em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } input.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } .wiktku-start-step { padding: 0.5em 0.6em; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } html.skin-theme-clientpref-night .wiktku-start-step { box-shadow: none; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } 6vdc7sxwd6atyweczesmgh0xazak336 6291822 6291716 2026-07-28T07:28:49Z Wikihez 7344 6291822 css text/css /* Requires MediaWiki:Gadget-Palette.css for the --wikt-palette-* vars. */ /* =================================================================== Base scale Everything under the form is scaled down a notch and given a tighter line-height. This is the single biggest lever on "too much scrolling": at 100% + default line-height, ~30 form steps easily doubles the page height compared to 92% + 1.35 line-height. =================================================================== */ #wiktku-start-form, #wiktku-preview-container { font-size: 0.92em; line-height: 1.35; } #wiktku-start-form * , #wiktku-preview-container * { box-sizing: border-box; } .wiktku-addlang-notice { margin: 0 0 0.8em; padding: 0.6em 0.8em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 4px; } /* =================================================================== Step cards Was: padding: 1em 0 + border-bottom (a flat divider list). Now: a compact card with a left accent bar, so each step reads as a distinct unit without needing a full em of air above and below it. =================================================================== */ .wiktku-start-step { padding: 0.55em 0.7em; margin-bottom: 0.4em; border: 1px solid var(--wikt-palette-grey-3, #e0e0e0); border-left: 3px solid var(--wikt-palette-blue-9, #3366cc); border-radius: 3px; background: var(--wikt-palette-white); transition: border-left-color 0.15s ease; } .wiktku-start-step:focus-within { border-left-color: var(--wikt-palette-blue-9, #3366cc); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); } .wiktku-start-step-question { font-size: 104%; font-weight: 600; margin: 0 0 0.35em; line-height: 1.3; } .wiktku-start-step label { padding-right: 1.2em; font-size: 0.95em; } input[type="text"].wiktku-start-step-field { width: 100%; padding: 4px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; } input[type="text"].wiktku-start-step-field.wiktku-start-narrow { width: 20em; } /* Only used by selects that opt out via .wiktku-plain-select; other selects get their width from the searchable picker instead (see input.wiktku-ac-input). */ select.wiktku-start-narrow, input.wiktku-dfn-tpl-title { width: 20em; max-width: 100%; box-sizing: border-box; } #wiktku-start-spinner { float: right; margin-left: 1em; } #wiktku-start-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em; padding: 0.6em 0.2em; position: sticky; bottom: 0; background: var(--wikt-palette-white); border-top: 1px solid var(--wikt-palette-grey-3, #e0e0e0); z-index: 5; } /* ── "Bişîne" click feedback ── A toast alone is easy to miss, and the disabled/spinner state only appears once getWikitext resolves. This gives an instant, unmissable confirmation the click registered, right at the point of contact. */ @keyframes wiktku-btn-flash-pulse { 0% { box-shadow: 0 0 0 0 rgba(51, 102, 204, 0.55); } 70% { box-shadow: 0 0 0 9px rgba(51, 102, 204, 0); } 100% { box-shadow: 0 0 0 0 rgba(51, 102, 204, 0); } } #wiktku-unhide-editform.wiktku-btn-flash { animation: wiktku-btn-flash-pulse 0.5s ease-out; } /* Persistent state while the wikitext is being built/submitted, set alongside OOUI's own setDisabled(true) so it reads clearly even if the skin's default disabled style is subtle. */ #wiktku-unhide-editform.wiktku-btn-sending .oo-ui-buttonElement-button { background-color: var(--wikt-palette-grey-9, #767676) !important; border-color: var(--wikt-palette-grey-9, #767676) !important; cursor: progress; opacity: 1 !important; } #wiktku-start-form textarea.wiktku-start-step-field, #wiktku-start-form textarea.wiktku-start-narrow, #wiktku-start-form textarea.wiktku-dfn-subfield { resize: vertical !important; overflow: auto !important; box-sizing: border-box !important; vertical-align: top; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; transition: border-color 0.1s ease, box-shadow 0.1s ease; } /* Modern focus state to match the searchable-picker inputs. */ #wiktku-start-form textarea.wiktku-start-step-field:focus, #wiktku-start-form textarea.wiktku-start-narrow:focus, #wiktku-start-form textarea.wiktku-dfn-subfield:focus { border-color: var(--wikt-palette-blue-9, #3366cc); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9, #3366cc); outline: 0; } #wiktku-start-form textarea.wiktku-start-narrow, #wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow { width: 20em; max-width: 100%; min-width: 8em; height: calc(1.7em + 10px); min-height: calc(1.7em + 10px); padding-top: 4px !important; padding-bottom: 4px !important; line-height: 1.35 !important; /* These are one-line fields (Etîket, Hevmane, Dijmane, Dûnde/Jê/Têkildar/ Binêre herwiha word boxes, citation source fields, …) — dragging them taller/wider doesn't make sense and was the cause of boxes sticking out past the step card on mobile. See .wiktku-dfn-quote-src-input--title below for the one deliberate exception (citation title fields). */ resize: none !important; } /* Exception: "Sernav" / "Sernavê orjînal" citation-source fields (kitêb, kovar, malper, …) — long enough to be worth 2 rows and manual resizing. */ #wiktku-start-form textarea.wiktku-dfn-quote-src-input.wiktku-dfn-quote-src-input--title { height: calc(2 * 1.35em + 10px); min-height: calc(2 * 1.35em + 10px); resize: vertical !important; } /* =================================================================== Searchable dropdown (wrapNativeSelect in start.js) .wiktku-native-select-wrap > input.wiktku-ac-input (search box) > ul.wiktku-ac-results (result list) > select (hidden, holds the value) =================================================================== */ .wiktku-native-select-wrap { display: inline-block; position: relative; vertical-align: top; } /* Matches the width the native select would have had (see select.wiktku-start-narrow). */ .wiktku-native-select-wrap input[type="search"], input.wiktku-ac-input { display: block; width: 20em; max-width: 100%; box-sizing: border-box; padding: 3px 6px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 2px; background: var(--wikt-palette-white); color: inherit; font-size: inherit; font-family: inherit; transition: border-color 0.1s ease, box-shadow 0.1s ease; } input.wiktku-ac-input:focus { border-color: var(--wikt-palette-blue-9); box-shadow: inset 0 0 0 1px var(--wikt-palette-blue-9); outline: 0; } input.wiktku-ac-input::placeholder { color: var(--wikt-palette-grey-9); opacity: 1; } /* Hide Safari/Chrome's built-in search decorations. */ input.wiktku-ac-input::-webkit-search-decoration, input.wiktku-ac-input::-webkit-search-cancel-button, input.wiktku-ac-input::-webkit-search-results-button { -webkit-appearance: none; appearance: none; } /* ── Result list ── */ /* top/bottom/max-height are overridden inline by showResults() when it flips the list above the box; these are just its defaults. */ ul.wiktku-ac-results { position: absolute; z-index: 9999; top: 100%; bottom: auto; left: 0; margin: 0; padding: 0; list-style: none; width: 20em; max-width: 90vw; max-height: 13em; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--wikt-palette-white); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15); } ul.wiktku-ac-results li { margin: 0; padding: 4px 8px; cursor: pointer; font-size: 0.92em; display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* .wiktku-ac-active is the keyboard cursor; hover mirrors it; :active covers the touch press state. */ ul.wiktku-ac-results li.wiktku-ac-active, ul.wiktku-ac-results li:hover { background: var(--wikt-palette-lightblue); } ul.wiktku-ac-results li:active { background: var(--wikt-palette-blue-9); color: var(--wikt-palette-white); } /* Touch devices: bigger tap targets, no sticky hover. */ @media (pointer: coarse) { ul.wiktku-ac-results li { padding: 6px 10px; min-height: 2.2em; font-size: 1em; } ul.wiktku-ac-results li:hover { background: transparent; } ul.wiktku-ac-results li.wiktku-ac-active { background: var(--wikt-palette-lightblue); } input.wiktku-ac-input { /* >=16px stops iOS Safari zooming the page when the box is focused. */ font-size: 16px; min-height: 2.2em; } } /* Template pickers fill their container since the search box, not the <select>, is what the user sees. */ .wiktku-pron-wrap .wiktku-native-select-wrap, .wiktku-etym-wrap .wiktku-native-select-wrap, .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } .wiktku-cavkani-wrap .wiktku-native-select-wrap, .wiktku-cavkani-wrap .wiktku-native-select-wrap input.wiktku-ac-input { width: 100%; } /* Template selector inside a sense block. */ .wiktku-dfn-tpl-row .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 0.88em; } /* Language/dialect rows: picker must line up with the word field beside it. */ .wiktku-lang-row .wiktku-native-select-wrap { flex: 0 0 auto; } /* ── Wikitext preview panel ── */ #wiktku-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; white-space: pre-wrap; word-break: break-word; font-family: monospace; font-size: 0.85em; } /* ── Live rendered preview panel (desktop only) ── */ #wiktku-live-preview-panel { margin-top: 0.8em; padding: 0.7em; background: var(--wikt-palette-paleblue); border: 1px solid var(--wikt-palette-lightgrey); border-radius: 3px; word-break: break-word; min-height: 2em; } /* ── Preview container (holds wikitext + live panels) ── */ #wiktku-preview-container { display: flex; flex-wrap: wrap; gap: 0.8em; margin-top: 0.4em; } #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-start-form textarea.wiktku-cavkani-text, #wiktku-start-form textarea.wiktku-dfn-werger { --wiktku-ta-rows: 2; width: 100%; box-sizing: border-box; height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); min-height: calc(var(--wiktku-ta-rows) * 1.35em + 6px); } #wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text, #wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text, #wiktku-start-form textarea.wiktku-dfn-izah { --wiktku-ta-rows: 3; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 4; } /* Nimûne + Jêgirtin (citation) boxes, and their tr/t sub-fields: at least 4 rows so there's room to actually write an example/quote. */ #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-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: 4; } /* ── Werger + Îzah boxes (non-ku alternative to the plain mane box) ── */ .wiktku-dfn-nonku-wrap { display: flex; flex-direction: column; gap: 3px; } .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.35 !important; font-size: 0.88em; } /* ── Template selector row inside a sense block ── */ .wiktku-dfn-tpl-row { margin-bottom: 3px; } /* ── Sub-field titles (Etîket, Kategorî, Hevmane, Dijmane, Nimûne, Jêgirtin, …) — previously plain unstyled run-on text. Each group now reads as a small labelled field: the term stands out, the izah hint stays quiet, and the block gets its own breathing room. ── */ .wiktku-dfn-subgroup { margin-top: 0.5em; padding-top: 0.4em; border-top: 1px dashed var(--wikt-palette-grey-3, #e0e0e0); } .wiktku-dfn-subgroup:first-of-type { margin-top: 0.3em; padding-top: 0; border-top: none; } .wiktku-dfn-sublabel { display: block; margin-bottom: 3px; font-size: 0.88em; } .wiktku-dfn-sublabel-term { font-weight: 600; color: var(--wikt-palette-blue-9, #3366cc); text-transform: uppercase; letter-spacing: 0.03em; font-size: 0.92em; } .wiktku-dfn-sublabel-hint { color: var(--wikt-palette-grey-9, #767676); font-style: italic; } .wiktku-pron-wrap, .wiktku-etym-wrap, .wiktku-cavkani-wrap { display: flex; flex-direction: column; gap: 3px; } /* ── POS section tabs ── Modernized into rounded pills instead of flat file-folder tabs. */ #wiktku-section-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 0.6em; align-items: center; } #wiktku-section-tabs .wiktku-section-tab { padding: 3px 12px; border: 1px solid var(--wikt-palette-lightgrey); border-radius: 999px; background: var(--wikt-palette-dullcyan); cursor: pointer; font-size: 0.86em; user-select: none; transition: background 0.12s ease, border-color 0.12s ease; } #wiktku-section-tabs .wiktku-section-tab:hover { border-color: var(--wikt-palette-blue-9, #3366cc); } #wiktku-section-tabs .wiktku-section-tab.wiktku-tab-active { background: var(--wikt-palette-blue-9, #3366cc); border-color: var(--wikt-palette-blue-9, #3366cc); color: var(--wikt-palette-white); font-weight: 600; } .wiktku-lang-row-list { margin: 0; padding: 0; list-style: none; } .wiktku-lang-row { display: flex; align-items: flex-start; gap: 6px; margin-bottom: 3px; flex-wrap: wrap; } .wiktku-lang-row-words { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 3px; } /* Dûnde/Werger/Zarava rows: align the picker's height with the adjacent word textarea (see .wiktku-start-narrow above). */ .wiktku-lang-row .wiktku-native-select-wrap input.wiktku-ac-input { height: calc(1.7em + 10px); min-height: calc(1.7em + 10px); padding-top: 4px; padding-bottom: 4px; } /* ── Werger / Bi zaravayên din groups: one per gloss, shared spacing ── */ #wiktku-start-trans .wiktku-trans-group, #wiktku-start-zarava .wiktku-zarava-group { margin-bottom: 0.6em; } #wiktku-start-trans .wiktku-trans-group:last-child, #wiktku-start-zarava .wiktku-zarava-group:last-child { margin-bottom: 0; } #wiktku-start-trans .wiktku-trans-group-label, #wiktku-start-zarava .wiktku-zarava-group-label { font-weight: 600; font-size: 0.88em; margin-bottom: 3px; } .wiktku-dfn-jeder-group { margin-top: 3px; } /* Drag handle for reordering citation rows */ .wiktku-jeder-drag-handle { display: inline-block; cursor: grab; color: var(--wikt-palette-lightgrey, #ccc); font-size: 1.15em; line-height: 1; margin-right: 4px; vertical-align: middle; user-select: none; } .wiktku-jeder-drag-handle:active { cursor: grabbing; } .wiktku-dfn-jeder-list .ui-sortable-placeholder { border: 2px dashed var(--wikt-palette-lightgrey, #ccc); background: transparent; visibility: visible !important; height: 1.8em; } .wiktku-dfn-quote-src-sel { font-size: 0.88em; margin-top: 3px; display: block; } .wiktku-dfn-quote-src-fields { display: flex; flex-direction: column; gap: 3px; margin-top: 3px; } .wiktku-dfn-quote-citoid { display: flex; align-items: center; flex-wrap: wrap; gap: 0.4em; margin-bottom: 3px; } input.wiktku-dfn-quote-citoid-input { flex: 1 1 24em; width: 24em; max-width: 100%; box-sizing: border-box; } .wiktku-dfn-quote-src-cat-status { display: block; font-size: 0.82em; color: var(--wikt-palette-lightgrey, #767676); margin-top: 2px; } .wiktku-dfn-quote-src-row { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; } .wiktku-dfn-quote-src-row label { font-size: 0.82em; white-space: nowrap; min-width: 8em; } textarea.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; } /* Single column: search box and list use the full width. Narrow textareas (Etîket, Hevmane, Dûnde/Jê/Têkildar/Binêre herwiha word boxes, citation source fields, …) join them here too — at a fixed 20em width they used to poke out past the step card on narrow screens. */ .wiktku-native-select-wrap, input.wiktku-ac-input, ul.wiktku-ac-results, #wiktku-start-form textarea.wiktku-start-narrow, #wiktku-start-form textarea.wiktku-dfn-subfield.wiktku-start-narrow { width: 100%; max-width: 100%; } #wiktku-start-form textarea.wiktku-dfn-mane, #wiktku-start-form .wiktku-pron-wrap textarea.wiktku-pron-text, #wiktku-start-form .wiktku-etym-wrap textarea.wiktku-etym-text { --wiktku-ta-rows: 3; font-size: 1em; } #wiktku-start-form textarea.wiktku-cavkani-text { --wiktku-ta-rows: 5; font-size: 1em; } /* Nimûne + Jêgirtin and their tr/t sub-fields: keep at least 4 rows on mobile too, rather than shrinking further than the desktop size. */ #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-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: 4; font-size: 1em; } /* Citoid URL/DOI/ISBN box: taller tap target (~2 lines) on mobile. */ input.wiktku-dfn-quote-citoid-input { min-height: calc(2 * 1.35em + 10px); font-size: 1em; } .wiktku-dfn-nimune-sub, .wiktku-dfn-quote-sub { margin-left: 0.5em; padding-left: 0.4em; } .wiktku-pron-wrap .wiktku-native-select-wrap input.wiktku-ac-input, .wiktku-etym-wrap .wiktku-native-select-wrap input.wiktku-ac-input { font-size: 1em; min-height: 2.2em; } .wiktku-dfn-quote-src-row label { min-width: 6em; } #wiktku-start-form textarea.wiktku-dfn-quote-src-input, input.wiktku-dfn-quote-citoid-input { width: 100%; flex: 1 1 100%; } .wiktku-start-step { padding: 0.5em 0.6em; } } /* =================================================================== Night mode Palette.css already flips every --wikt-palette-* var for night mode, so rules built from those vars need nothing here. This hook is only for real colours that can't be a palette var — here, the panel border, since a drop shadow is invisible against an equally dark page. Not needed: li:active's white text already flips to a dark colour at night via --wikt-palette-white, so it stays legible on its own. =================================================================== */ @media screen { html.skin-theme-clientpref-night .wiktku-ac-results { /* Border stands in for the shadow, invisible on a dark page. */ border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } html.skin-theme-clientpref-night .wiktku-start-step { box-shadow: none; } } @media screen and (prefers-color-scheme: dark) { html.skin-theme-clientpref-os .wiktku-ac-results { border-color: var(--wikt-palette-grey-5); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.6); } } /* "Zimanek lê zêde bike" portlet icon (Minerva/mobile) — Feather-core-edit.svg via CSS mask, matching Minerva's own icon pattern. */ .minerva-icon-portletlink-ca-wiktku-addlang { -webkit-mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); mask-image: url("https://upload.wikimedia.org/wikipedia/commons/d/d7/Feather-core-edit.svg"); -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; -webkit-mask-size: 20px; mask-size: 20px; background-color: currentColor; background-image: none; } 9z530spq30mfvl5d187oltvkyff0x70 Gotûbêja bikarhêner:Mehmet Can Demir 3 1358191 6291640 2026-07-27T13:10:07Z Wikihez 7344 xêrhatin lê zêde kir 6291640 wikitext text/x-wiki {{bixêrhatin}} == Xêrhatin == Merheba bikarhênera/ê me ya/ê hêja: ''Mehmet Can Demir'', 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]]) 13:10, 27 tîrmeh 2026 (UTC) ec5u0ahcn50064gskrs8zyabmb5cs7t 6291641 6291640 2026-07-27T13:11:07Z Wikihez 7344 /* Xêrhatin */ Bersiv 6291641 wikitext text/x-wiki {{bixêrhatin}} == Xêrhatin == Merheba bikarhênera/ê me ya/ê hêja: ''Mehmet Can Demir'', 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]]) 13:10, 27 tîrmeh 2026 (UTC) :Merheba tu dikarî rûpela [[wezreba]] çêkî û li pêşiya bi parantezê deverê binivîsî ya ku lê tê bikaranîn? [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:11, 27 tîrmeh 2026 (UTC) bp06x9vmzrieqx6cnke80kv641t0jir 6291644 6291641 2026-07-27T13:14:14Z Wikihez 7344 /* Xêrhatin */ 6291644 wikitext text/x-wiki {{bixêrhatin}} == Xêrhatin == Merheba bikarhênera/ê me ya/ê hêja: ''Mehmet Can Demir'', 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]]) 13:10, 27 tîrmeh 2026 (UTC) :Merheba tu dikarî rûpela [[wezreba]] çêkî û li pêşiya bi parantezê deverê binivîsî ya ku lê tê bikaranîn? Bi vê formatê {{demo|sep=ku wisa xuya dibe|<nowiki>{{e|ku|Qerejdax}}</nowiki>}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:11, 27 tîrmeh 2026 (UTC) pgryb3vvfoof8euma5hgibdt53cgl1w 6291650 6291644 2026-07-27T13:55:31Z Mehmet Can Demir 11086 /* Xêrhatin */ Bersiv 6291650 wikitext text/x-wiki {{bixêrhatin}} == Xêrhatin == Merheba bikarhênera/ê me ya/ê hêja: ''Mehmet Can Demir'', 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]]) 13:10, 27 tîrmeh 2026 (UTC) :Merheba tu dikarî rûpela [[wezreba]] çêkî û li pêşiya bi parantezê deverê binivîsî ya ku lê tê bikaranîn? Bi vê formatê {{demo|sep=ku wisa xuya dibe|<nowiki>{{e|ku|Qerejdax}}</nowiki>}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:11, 27 tîrmeh 2026 (UTC) :[{Bedlîs•Hîzan}] [[Bikarhêner:Mehmet Can Demir|Mehmet Can Demir]] ([[Gotûbêja bikarhêner:Mehmet Can Demir#top|gotûbêj]]) 13:55, 27 tîrmeh 2026 (UTC) e0zb9edikte7j80b8vvachkd47qq50q 6291656 6291650 2026-07-27T14:50:16Z Wikihez 7344 /* Xêrhatin */ Bersiv 6291656 wikitext text/x-wiki {{bixêrhatin}} == Xêrhatin == Merheba bikarhênera/ê me ya/ê hêja: ''Mehmet Can Demir'', 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]]) 13:10, 27 tîrmeh 2026 (UTC) :Merheba tu dikarî rûpela [[wezreba]] çêkî û li pêşiya bi parantezê deverê binivîsî ya ku lê tê bikaranîn? Bi vê formatê {{demo|sep=ku wisa xuya dibe|<nowiki>{{e|ku|Qerejdax}}</nowiki>}} [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 13:11, 27 tîrmeh 2026 (UTC) :[{Bedlîs•Hîzan}] [[Bikarhêner:Mehmet Can Demir|Mehmet Can Demir]] ([[Gotûbêja bikarhêner:Mehmet Can Demir#top|gotûbêj]]) 13:55, 27 tîrmeh 2026 (UTC) ::[https:{{fullurl:wezreba|action=submit}} wezreba] pê li vê lînkê bike, formek dê were pêşberî te, li wir ziman kurmancî hilbijêre û dûre maneyê binivîse, dûre pê li "Bişîne" bike [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:50, 27 tîrmeh 2026 (UTC) kvz7dd75a7nl1g01m0s1j8itvmnlr3v Gotûbêj:dutayî 1 1358192 6291657 2026-07-27T14:54:40Z Wikihez 7344 /* Dutayî */ beşeke nû 6291657 wikitext text/x-wiki == Dutayî == Merheba @[[Bikarhêner:Keyomerd|Keyomerd]], Dutayî bi vê maneyê bê çavkanî ye, ez [[cotreh]] / {{ferhengok|cotreh}} li şûna wê bi kar tînim, ew jî bêçavkanî ye loma min sayfeya wê çênekiriye, heta were peyitandin em li ferhengokê {{ferhengok|dutayî}} dutayî qeyd bikin baştir e. Em ji her kesî çavkanî dixwazin rabin kelîmeyên bêçavkanî wekî çavkanî qeyd bikin ne tiştekî normal e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:54, 27 tîrmeh 2026 (UTC) mp2kkat39er7tu86do4ahbgq6z0fws4 6291659 6291657 2026-07-27T14:55:35Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291659 wikitext text/x-wiki == Dutayî == Merheba @[[Bikarhêner:Keyomerd|Keyomerd]], Dutayî bi vê maneyê bê çavkanî ye, ez [[cotreh]] / {{ferhengok|cotreh}} li şûna wê bi kar tînim, ew jî bêçavkanî ye loma min sayfeya wê çênekiriye, heta were peyitandin em li ferhengokê {{ferhengok|dutayî}} dutayî qeyd bikin baştir e. Em ji her kesî çavkanî dixwazin rabin kelîmeyên bêçavkanî bêyî çavkanî qeyd bikin ne tiştekî normal e. [[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 14:54, 27 tîrmeh 2026 (UTC) m8kjkd8cynm9ix8sap4ybckuwktsey9 Şablon:ku-tewîna-nav 10 1358193 6291667 2026-07-27T16:00:14Z Wikihez 7344 Rûpel bi "<includeonly>{{#invoke:ku-tewîn-nav/form/text|formOfText}}</includeonly><noinclude> {{belgekirin}} </noinclude>" hat çêkirin 6291667 wikitext text/x-wiki <includeonly>{{#invoke:ku-tewîn-nav/form/text|formOfText}}</includeonly><noinclude> {{belgekirin}} </noinclude> askmg3hm6it10fpav6t9i8m64a0qhh2 Şablon:ku-tewîna-nav/belge 10 1358194 6291669 2026-07-27T16:04:56Z Wikihez 7344 Rûpel bi "{{belgekirin/binrûpel}} == Bikaranîn == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablon]] </includeonly>" hat çêkirin 6291669 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablon]] </includeonly> 1g5nrb314d1xsdtchc8ydqm5eorwruf 6291670 6291669 2026-07-27T16:06:44Z Wikihez 7344 6291670 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|navdêr|cinsiyet "mê", "nêr" yan jî "mê û nêr"}}</nowiki></code> , == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablon]] </includeonly> qv16je682mjpwuvofg6cap45704bhp9 6291671 6291670 2026-07-27T16:07:12Z Wikihez 7344 6291671 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|navdêr|cinsiyet "mê", "nêr" yan jî "mê û nêr"}}</nowiki></code> , == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablonên navdêrên kurmancî]] </includeonly> h7pw0wl20mnmb4g294s1qmua5caok5o 6291672 6291671 2026-07-27T16:07:44Z Wikihez 7344 6291672 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|<navdêr ne tewandî>|<cinsiyet "mê", "nêr" yan jî "mê û nêr">}}</nowiki></code> , == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablonên navdêrên kurmancî]] </includeonly> e47q3uhoocwdbzty9ipjcwcxiss6t7m 6291673 6291672 2026-07-27T16:09:07Z Wikihez 7344 6291673 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|<navdêr ne tewandî>|<cinsiyet "mê", "nêr" yan jî "mê û nêr">}}</nowiki></code> , == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablonên navdêrên kurmancî]] </includeonly> <templatedata> { "params": { "1": { "label": "Navdêra ku were tewandin" }, "2": { "label": "Cinsiyeta kelîmeyê", "suggestedvalues": [ "mê", "nêr", "mê û nêr" ] }, "f": { "label": "Navê rûpelê", "description": "ji bo nîşandana vê şablonê li rûpelên din" } } } </templatedata> qx966kd5fh24cey68m71uulhs4fhdgz 6291674 6291673 2026-07-27T16:09:33Z Wikihez 7344 /* */ bi [[MediaWiki:Gadget-AjaxEdit.js|AjaxEdit]]ê re 6291674 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|<navdêr ne tewandî>|<cinsiyet "mê", "nêr" yan jî "mê û nêr">}}</nowiki></code> == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. <includeonly> [[Kategorî:Şablonên navdêrên kurmancî]] </includeonly> <templatedata> { "params": { "1": { "label": "Navdêra ku were tewandin" }, "2": { "label": "Cinsiyeta kelîmeyê", "suggestedvalues": [ "mê", "nêr", "mê û nêr" ] }, "f": { "label": "Navê rûpelê", "description": "ji bo nîşandana vê şablonê li rûpelên din" } } } </templatedata> 5s69l4f0y7wbu7rwmhzvijf2p5npb02 6291689 6291674 2026-07-27T19:09:18Z Ghybu 1393 /* Nimûne */ 6291689 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|<navdêr ne tewandî>|<cinsiyet "mê", "nêr" yan jî "mê û nêr">}}</nowiki></code> == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. Ji bo formên '''nestandard''' wekî ''bajêr'', ''welêt'', ''êş'', ... paşgirên formên standard ({{param2|f|-ê, -î, -a, ...}}) binivîsin: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|aş|nêr|f=-î}}</nowiki>}} <includeonly> [[Kategorî:Şablonên navdêrên kurmancî]] </includeonly> <templatedata> { "params": { "1": { "label": "Navdêra ku were tewandin" }, "2": { "label": "Cinsiyeta kelîmeyê", "suggestedvalues": [ "mê", "nêr", "mê û nêr" ] }, "f": { "label": "Navê rûpelê", "description": "ji bo nîşandana vê şablonê li rûpelên din" } } } </templatedata> jwg3eptnwnwhywount0pmaj5625wwr7 6291719 6291689 2026-07-27T21:50:28Z Wikihez 7344 /* Nimûne */ 6291719 wikitext text/x-wiki {{belgekirin/binrûpel}} == Bikaranîn == * <code><nowiki>{{ku-tewîna-nav|<navdêr ne tewandî>|<cinsiyet "mê", "nêr" yan jî "mê û nêr">}}</nowiki></code> == Nimûne == Di rûpela {{q|ku|hevalê}} de: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|heval|mê û nêr|f=hevalê}}</nowiki>}} Parametreya {{param|f}} ji bo nîşandana li rûpelên din de tê bikaranîn, di rûpela {{q|ku|hevalê}} de ne hewce ye. Ji bo formên '''nestandard''' wekî ''bajêr'', ''welêt'', ''êş'', ... paşgirên formên standard ({{param2|f|-ê, -î, -a, ...}}) binivîsin: {{demo|sep=dide|<nowiki> # {{ku-tewîna-nav|aş|nêr|f=-î}}</nowiki>}} == TemplateData== {{TemplateData header}} <templatedata> { "params": { "1": { "label": "Navdêra ku were tewandin" }, "2": { "label": "Cinsiyeta kelîmeyê", "suggestedvalues": [ "mê", "nêr", "mê û nêr" ] }, "f": { "label": "Navê rûpelê", "description": "ji bo nîşandana vê şablonê li rûpelên din" } }, "description": "Ji bo navdêrên kurmancî îzaha nemaneyî otomatîk çêdike li gorî herfa dawî ya navê formê di sernavê rûpelê de", "format": "inline" } </templatedata> <includeonly> [[Kategorî:Şablonên navdêrên kurmancî]] </includeonly> 7kkc6sx6vroa5hrawntcqbxacheeaaj mutesewif 0 1358195 6291680 2026-07-27T18:18:50Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +ku:navdêr:Kesê ku bi eqîdeya tesewufê ve eleqedar e û xwe teslîmî riya Xwedê kiriye. 6291680 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewif|mê û nêr}} {{navdêr|ku|c=mn}} # {{e|ku|Îslam|tesewif}} [[kes|Kesê]] ku bi [[eqîde]]ya [[tesewif]]ê ve [[eleqedar]] e û [[xwe]] [[teslîm]]î [[rê|riya]] [[Xwedê]] [[kirin|kiriye]]. #: {{alt-r|ku|mutesewuf|mutesewûf|mûtesewûf}} #* {{jêder-kovar|ku|jêgirtin=Qutbê Exlatî hem ji aliyê tesewifê û hem jî ji aliyê edebî bandorekê li ser şair û arifên li dû xwe kiriye. Wek mînak şair û mutesewifê Îranî, Nûr ‘Elîşahê Îsfehanî (kd. 1797) jî yek ji wan e.|nivîskar=Yakup Aykaç; Veysel Başçı|sernav=Dahûrîneke Tesewifî li Ser Qesîdeya “Çelebî” ya Şêx Şemsedînê Qutbê Exlatî|kovar=Kurdiname|hejmar=7|sal=2022|rûpel=74–103|url=https://dergipark.org.tr/en/pub/kurdiname/article/1203719}} ==== Têkildar ==== * {{g|ku|tesewif}} ==== Etîmolojî ==== Ji {{deyn|ar|ku|مُتَصَوِّف}}. ==== Werger ==== {{werger-ser|kesê ku bi eqîdeya tesewifê ve eleqedar e û xwe teslîmî riya Xwedê kiriye|1}} * {{Z|tr}}: {{W|tr|mutasavvıf}} {{werger-bin}} g0s5rrc0giht1jrtnib3bc0bd20j3qo 6291681 6291680 2026-07-27T18:19:06Z Wikihez 7344 6291681 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewif|mê û nêr}} {{navdêr|ku|c=mn}} # {{e|ku|Îslam|tesewif}} [[kes|Kesê]] ku bi [[eqîde]]ya [[tesewif]]ê ve [[eleqedar]] e û [[xwe]] [[teslîm]]î [[rê|riya]] [[Xwedê]] [[kirin|kiriye]]. #: {{alt-r|ku|mutesewuf|mutesewûf|mûtesewûf}} #* {{jêder-kovar|ku|jêgirtin=Qutbê Exlatî hem ji aliyê tesewifê û hem jî ji aliyê edebî bandorekê li ser şair û arifên li dû xwe kiriye. Wek mînak şair û '''mutesewifê''' Îranî, Nûr ‘Elîşahê Îsfehanî (kd. 1797) jî yek ji wan e.|nivîskar=Yakup Aykaç; Veysel Başçı|sernav=Dahûrîneke Tesewifî li Ser Qesîdeya “Çelebî” ya Şêx Şemsedînê Qutbê Exlatî|kovar=Kurdiname|hejmar=7|sal=2022|rûpel=74–103|url=https://dergipark.org.tr/en/pub/kurdiname/article/1203719}} ==== Têkildar ==== * {{g|ku|tesewif}} ==== Etîmolojî ==== Ji {{deyn|ar|ku|مُتَصَوِّف}}. ==== Werger ==== {{werger-ser|kesê ku bi eqîdeya tesewifê ve eleqedar e û xwe teslîmî riya Xwedê kiriye|1}} * {{Z|tr}}: {{W|tr|mutasavvıf}} {{werger-bin}} jfveblkz97p46jy03xmgmnc0inob7o9 6291733 6291681 2026-07-27T22:55:31Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +ku:rengdêr:Wekî mutesewifan, eleqedarî mutesewifan 6291733 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Etîmolojî === Ji {{deyn|ar|ku|مُتَصَوِّف}}. === Navdêr === {{ku-tewîn-nav|mutesewif|mê û nêr}} {{navdêr|ku|c=mn}} # {{e|ku|Îslam|tesewif}} [[kes|Kesê]] ku bi [[eqîde]]ya [[tesewif]]ê ve [[eleqedar]] e û [[xwe]] [[teslîm]]î [[rê|riya]] [[Xwedê]] [[kirin|kiriye]]. #: {{alt-r|ku|mutesewuf|mutesewûf|mûtesewûf}} #* {{jêder-kovar|ku|jêgirtin=Qutbê Exlatî hem ji aliyê tesewifê û hem jî ji aliyê edebî bandorekê li ser şair û arifên li dû xwe kiriye. Wek mînak şair û '''mutesewifê''' Îranî, Nûr ‘Elîşahê Îsfehanî (kd. 1797) jî yek ji wan e.|nivîskar=Yakup Aykaç; Veysel Başçı|sernav=Dahûrîneke Tesewifî li Ser Qesîdeya “Çelebî” ya Şêx Şemsedînê Qutbê Exlatî|kovar=Kurdiname|hejmar=7|sal=2022|rûpel=74–103|url=https://dergipark.org.tr/en/pub/kurdiname/article/1203719}} ==== Têkildar ==== * {{g|ku|tesewif}} ==== Werger ==== {{werger-ser|kesê ku bi eqîdeya tesewifê ve eleqedar e û xwe teslîmî riya Xwedê kiriye|1}} * {{Z|tr}}: {{W|tr|mutasavvıf}} {{werger-bin}} === Rengdêr === {{rengdêr|ku}} # [[wekî|Wekî]] mutesewifan, [[eleqedar]]î mutesewifan. #* {{jêder-kovar|ku|jêgirtin=Melayê Cizîrî jî, wekî şa’irekî mutesewif an mutesewifekî şa’ir, ji vê qaîdeyê mustesna nîne.|nivîskar=Shahab Vali; Cumhur Ölmez|sernav=Mîtolojî Û Tesewi̇f: Çemşîd û Camê Cem Dİ Dîwana Melayê Ci̇zîrî DE|kovar=Şarkiyat|cild=17|hejmar=1|sal=2025|rûpel=164|url=https://dergipark.org.tr/en/pub/sarkiat/article/1551814}} ==== Werger ==== {{werger-ser|wekî mutesewifan, eleqedarî mutesewifan|1}} {{werger-bin}} kpfr4oajahjjxhw7vfpxw4fcvl6wh33 6291734 6291733 2026-07-27T22:56:04Z Wikihez 7344 /* Rengdêr */ 6291734 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Etîmolojî === Ji {{deyn|ar|ku|مُتَصَوِّف}}. === Navdêr === {{ku-tewîn-nav|mutesewif|mê û nêr}} {{navdêr|ku|c=mn}} # {{e|ku|Îslam|tesewif}} [[kes|Kesê]] ku bi [[eqîde]]ya [[tesewif]]ê ve [[eleqedar]] e û [[xwe]] [[teslîm]]î [[rê|riya]] [[Xwedê]] [[kirin|kiriye]]. #: {{alt-r|ku|mutesewuf|mutesewûf|mûtesewûf}} #* {{jêder-kovar|ku|jêgirtin=Qutbê Exlatî hem ji aliyê tesewifê û hem jî ji aliyê edebî bandorekê li ser şair û arifên li dû xwe kiriye. Wek mînak şair û '''mutesewifê''' Îranî, Nûr ‘Elîşahê Îsfehanî (kd. 1797) jî yek ji wan e.|nivîskar=Yakup Aykaç; Veysel Başçı|sernav=Dahûrîneke Tesewifî li Ser Qesîdeya “Çelebî” ya Şêx Şemsedînê Qutbê Exlatî|kovar=Kurdiname|hejmar=7|sal=2022|rûpel=74–103|url=https://dergipark.org.tr/en/pub/kurdiname/article/1203719}} ==== Têkildar ==== * {{g|ku|tesewif}} ==== Werger ==== {{werger-ser|kesê ku bi eqîdeya tesewifê ve eleqedar e û xwe teslîmî riya Xwedê kiriye|1}} * {{Z|tr}}: {{W|tr|mutasavvıf}} {{werger-bin}} === Rengdêr === {{rengdêr|ku}} # [[wekî|Wekî]] mutesewifan, [[eleqedar]]î mutesewifan. #* {{jêder-kovar|ku|jêgirtin=Melayê Cizîrî jî, wekî şa’irekî '''mutesewif''' an mutesewifekî şa’ir, ji vê qaîdeyê mustesna nîne.|nivîskar=Shahab Vali; Cumhur Ölmez|sernav=Mîtolojî Û Tesewi̇f: Çemşîd û Camê Cem Dİ Dîwana Melayê Ci̇zîrî DE|kovar=Şarkiyat|cild=17|hejmar=1|sal=2025|rûpel=164|url=https://dergipark.org.tr/en/pub/sarkiat/article/1551814}} ==== Werger ==== {{werger-ser|wekî mutesewifan, eleqedarî mutesewifan|1}} {{werger-bin}} cvwu4wrrnyelwubf5tty4pt7y4jvr1t 6291744 6291734 2026-07-27T23:10:53Z Wikihez 7344 Werger: +îngilîzî : [[Sufi]] (bi alîkarî) 6291744 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Etîmolojî === Ji {{deyn|ar|ku|مُتَصَوِّف}}. === Navdêr === {{ku-tewîn-nav|mutesewif|mê û nêr}} {{navdêr|ku|c=mn}} # {{e|ku|Îslam|tesewif}} [[kes|Kesê]] ku bi [[eqîde]]ya [[tesewif]]ê ve [[eleqedar]] e û [[xwe]] [[teslîm]]î [[rê|riya]] [[Xwedê]] [[kirin|kiriye]]. #: {{alt-r|ku|mutesewuf|mutesewûf|mûtesewûf}} #* {{jêder-kovar|ku|jêgirtin=Qutbê Exlatî hem ji aliyê tesewifê û hem jî ji aliyê edebî bandorekê li ser şair û arifên li dû xwe kiriye. Wek mînak şair û '''mutesewifê''' Îranî, Nûr ‘Elîşahê Îsfehanî (kd. 1797) jî yek ji wan e.|nivîskar=Yakup Aykaç; Veysel Başçı|sernav=Dahûrîneke Tesewifî li Ser Qesîdeya “Çelebî” ya Şêx Şemsedînê Qutbê Exlatî|kovar=Kurdiname|hejmar=7|sal=2022|rûpel=74–103|url=https://dergipark.org.tr/en/pub/kurdiname/article/1203719}} ==== Têkildar ==== * {{g|ku|tesewif}} ==== Werger ==== {{werger-ser|kesê ku bi eqîdeya tesewifê ve eleqedar e û xwe teslîmî riya Xwedê kiriye|1}} * {{Z|en}}: {{W+|en|Sufi}} * {{Z|tr}}: {{W|tr|mutasavvıf}} {{werger-bin}} === Rengdêr === {{rengdêr|ku}} # [[wekî|Wekî]] mutesewifan, [[eleqedar]]î mutesewifan. #* {{jêder-kovar|ku|jêgirtin=Melayê Cizîrî jî, wekî şa’irekî '''mutesewif''' an mutesewifekî şa’ir, ji vê qaîdeyê mustesna nîne.|nivîskar=Shahab Vali; Cumhur Ölmez|sernav=Mîtolojî Û Tesewi̇f: Çemşîd û Camê Cem Dİ Dîwana Melayê Ci̇zîrî DE|kovar=Şarkiyat|cild=17|hejmar=1|sal=2025|rûpel=164|url=https://dergipark.org.tr/en/pub/sarkiat/article/1551814}} ==== Werger ==== {{werger-ser|wekî mutesewifan, eleqedarî mutesewifan|1}} {{werger-bin}} 6zqqcgl8i95ia9gcwml71hu72sqz367 Kategorî:Navdêrên kurmancî bi formên alternatîv 14 1358196 6291700 2026-07-27T20:21:59Z Ghybu 1393 6291700 wikitext text/x-wiki [[Kategorî:Navdêr bi kurmancî|!]] d1wgwlf1jf6mhgur1j9j6sztxhnv1dm 6291706 6291700 2026-07-27T20:31:15Z Ghybu 1393 Ghybuî/ê navê [[Kategorî:Navdêrên kurdî bi formên alternatîv]] weke [[Kategorî:Navdêrên kurmancî bi formên alternatîv]] guhart 6291700 wikitext text/x-wiki [[Kategorî:Navdêr bi kurmancî|!]] d1wgwlf1jf6mhgur1j9j6sztxhnv1dm Kategorî:Navdêrên kurmancî bi formên nestandard 14 1358197 6291702 2026-07-27T20:23:32Z Ghybu 1393 6291702 wikitext text/x-wiki [[Kategorî:Navdêr bi kurmancî|!]] d1wgwlf1jf6mhgur1j9j6sztxhnv1dm 6291709 6291702 2026-07-27T20:32:27Z Ghybu 1393 Ghybuî/ê navê [[Kategorî:Navdêrên kurdî bi formên nestandard]] weke [[Kategorî:Navdêrên kurmancî bi formên nestandard]] guhart 6291702 wikitext text/x-wiki [[Kategorî:Navdêr bi kurmancî|!]] d1wgwlf1jf6mhgur1j9j6sztxhnv1dm mutesewuf 0 1358200 6291724 2026-07-27T22:16:54Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +ku:navdêr: 6291724 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Ji bilî Mekke û Medîne, hin alim û '''mutesewıfên''' Kurd ku li medrese û tekyayên Bexda, Şam, Qahire û Stenbolê de perwerde bûn, mane li wan navendan û di navbera koma alim û sufiyan de cihekî rêzdar bi dest xistin.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=12|url=https://zenodo.org/record/4309785}} ==== Jê ==== * {{g|ku|tesewuf}} g6klwj9f008a54ll5ioh1qxezl5yuqa 6291725 6291724 2026-07-27T22:19:07Z Wikihez 7344 /* Navdêr */ 6291725 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Mewlana Xalid '''mutesewufekê''' Kurd li Şehrezorê bû.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=14|url=https://zenodo.org/record/4309785}} ==== Jê ==== * {{g|ku|tesewuf}} s5pzepslr0329pxcte7x3cpczsd4xww 6291726 6291725 2026-07-27T22:28:19Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +zza:navdêr:mutesewuf {{îzah|kesê bi tesewifê eleqedar}} 6291726 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Mewlana Xalid '''mutesewufekê''' Kurd li Şehrezorê bû.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=14|url=https://zenodo.org/record/4309785}} ==== Jê ==== * {{g|ku|tesewuf}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza}} # {{e|zza|Îslam|tesewif}} [[mutesewuf]] {{îzah|[[kes|kesê]] bi [[tesewif]]ê [[eleqedar]]}} #* {{bênimûne|zza}} ==== Etîmolojî ==== {{ji?|zza}} 9541sha73oa7342qf4yv21ulhmaqqj7 6291727 6291726 2026-07-27T22:28:58Z Wikihez 7344 /* Têkildar */ 6291727 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Mewlana Xalid '''mutesewufekê''' Kurd li Şehrezorê bû.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=14|url=https://zenodo.org/record/4309785}} ==== Têkildar ==== * {{g|ku|tesewuf}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza}} # {{e|zza|Îslam|tesewif}} [[mutesewuf]] {{îzah|[[kes|kesê]] bi [[tesewif]]ê [[eleqedar]]}} #* {{bênimûne|zza}} ==== Etîmolojî ==== {{ji?|zza}} h88yoc7yyunq618fdzjy6fz4j7kggwg 6291728 6291727 2026-07-27T22:30:21Z Wikihez 7344 +nimûneya bikaranînê bi amûra « [[Mediawiki:Gadget-wikt.add-examples|Nimûne zêde bike]] » (v1.7). 6291728 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Mewlana Xalid '''mutesewufekê''' Kurd li Şehrezorê bû.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=14|url=https://zenodo.org/record/4309785}} ==== Têkildar ==== * {{g|ku|tesewuf}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza}} # {{e|zza|Îslam|tesewif}} [[mutesewuf]] {{îzah|[[kes|kesê]] bi [[tesewif]]ê [[eleqedar]]}} #* {{jêder-kovar|zza|nivîskar=İbrahim Dağılma|sernav=Feqî (Bilal) Çolîg U Eseri Ey|kovar=Bingöl Araştırmaları Dergisi|hejmar=23|sal=2025|rûpel=1–21|url=https://dergipark.org.tr/tr/pub/bad/article/1800222|jêgirtin=Wı merdumê ko '''mutesewuf''' u şêxê dergahê Qelenderi yo. Tahir Uryan, Kurdanê Loran ra yo u heyatê xu welatê xu Loristan dı viyarnayo.}} ==== Etîmolojî ==== {{ji?|zza}} py7a900hvijgm67edylaepbj90i5t6d 6291729 6291728 2026-07-27T22:30:40Z Wikihez 7344 /* Navdêr */ 6291729 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Mewlana Xalid '''mutesewufekê''' Kurd li Şehrezorê bû.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=14|url=https://zenodo.org/record/4309785}} ==== Têkildar ==== * {{g|ku|tesewuf}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza}} # {{e|zza|Îslam|tesewif}} [[mutesewif]] {{îzah|[[kes|kesê]] bi [[tesewif]]ê [[eleqedar]]}} #* {{jêder-kovar|zza|nivîskar=İbrahim Dağılma|sernav=Feqî (Bilal) Çolîg U Eseri Ey|kovar=Bingöl Araştırmaları Dergisi|hejmar=23|sal=2025|rûpel=1–21|url=https://dergipark.org.tr/tr/pub/bad/article/1800222|jêgirtin=Wı merdumê ko '''mutesewuf''' u şêxê dergahê Qelenderi yo. Tahir Uryan, Kurdanê Loran ra yo u heyatê xu welatê xu Loristan dı viyarnayo.}} ==== Etîmolojî ==== {{ji?|zza}} 1gqmi6e5bmacjtefki3nfzwty7qkrcs 6291730 6291729 2026-07-27T22:31:04Z Wikihez 7344 /* Navdêr */ 6291730 wikitext text/x-wiki == {{ziman|ku}} == === Bilêvkirin === * {{ku-kîte}} === Navdêr === {{ku-tewîn-nav|mutesewuf|mê û nêr}} {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kovar|ku|jêgirtin=Mewlana Xalid '''mutesewufekê''' Kurd li Şehrezorê bû.|nivîskar=Abdulcebbar Kavak|sernav=Şopên Farisî Di Edebiyata Kurdî ya Tesewufî de|kovar=Kurdiyat|hejmar=2|sal=2020|rûpel=14|url=https://zenodo.org/record/4309785}} ==== Têkildar ==== * {{g|ku|tesewuf}} == {{ziman|zza}} == === Navdêr === {{navdêr|zza}} # {{e|zza|Îslam|tesewif}} [[mutesewif]] {{îzah|[[kes|kesê]] bi [[tesewif]]ê [[eleqedar]]}} #* {{jêder-kovar|zza|nivîskar=İbrahim Dağılma|sernav=Feqî (Bilal) Çolîg U Eseri Ey|kovar=Bingöl Araştırmaları Dergisi|hejmar=23|sal=2025|rûpel=1–21|url=https://dergipark.org.tr/tr/pub/bad/article/1800222|jêgirtin=Wı merdumê ko '''mutesewuf''' u şêxê dergahê Qelenderi yo. Tahir Uryan, Kurdanê Loran ra yo u heyatê xu welatê xu Loristan dı viyarnayo.}} ==== Etîmolojî ==== {{ji?|zza}} 9z2vl0od3iates6njl32nno511mxzor Kategorî:Îslam bi zazakî 14 1358201 6291731 2026-07-27T22:31:25Z Wikihez 7344 Bi riya [[Bikarhêner:Wikihez/skrîpt/js/addAutoCat.js/belge|JS]]: {{katbike}} û înterwîkî 6291731 wikitext text/x-wiki {{katbike}} 1dpx16ue3vl1l6c1hkqu0q6ftpl2ezh mutasavvıf 0 1358202 6291735 2026-07-27T22:59:04Z Wikihez 7344 ([[Bikarhêner:Wikihez/newentrywiz.js|NEC]]) +tr:navdêr: Bi [[Bikarhêner:Wikihez/CreateTranslation.js|amûrê]] ji wergerên [[mutesewif]]: 6291735 wikitext text/x-wiki == {{ziman|tr}} == === Navdêr === {{navdêr|tr}} # {{f|tr|Îslam}} [[mutesewif]] o2d691vdxx3q2vafs3y0cxa4k7ctsam 6291736 6291735 2026-07-27T23:00:07Z Wikihez 7344 /* {{ziman|tr}} */ [[Bikarhêner:Wikihez/templateScript2.js|TS]]: Ji [[en:mutasavvıf|en.wikt]] 6291736 wikitext text/x-wiki == {{ziman|tr}} == === Bilêvkirin === * {{IPA|tr|/mu.ta.sav.vɯf/}} === Navdêr === {{navdêr|tr}} # {{f|tr|Îslam}} [[mutesewif]] ==== Etîmolojî ==== Ji {{mîr|ota|tr|متصوف|tr=mutasavvıf}}, ji {{ji|ar|tr|مُتَصَوِّف}}. qi50jwbwpm6fh3uaq5qc7huuaumvonk Gotûbêj:sabûnsazxane 1 1358203 6291762 2026-07-27T23:34:41Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina nîqaşê ji rûpela [[Wîkîferheng:Daxwazên peyitandinê]] 6291762 wikitext text/x-wiki == Nîqaşa [[Wîkîferheng:Daxwazên peyitandinê|peyitandinê]] == {{arşîv-ser|dp|failed|link=Taybet:PermanentLink/6290845#sabûnsazxane}} {{fake==|1= <s>[[sabûnsazxane]]</s> }} ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' Xelet e û bêçavkanî ye. — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:24, 26 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:08, 17 tîrmeh 2026 (UTC) {{arşîv-bin}} rmmhumdd2oyzag72aov3i7xer7r1y5a Gotûbêj:bêonurane 1 1358204 6291763 2026-07-27T23:34:41Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Arşîvkirina nîqaşê ji rûpela [[Wîkîferheng:Daxwazên peyitandinê]] 6291763 wikitext text/x-wiki == Nîqaşa [[Wîkîferheng:Daxwazên peyitandinê|peyitandinê]] == {{arşîv-ser|dp|failed|link=Taybet:PermanentLink/6290845#bêonurane}} {{fake==|1= <s>[[bêonurane]]</s> }} ''[[Wîkîferheng:Pîvekên tevlîkirinê|Çavkanî hewce ye]].'' — [[Bikarhêner:Bikarhêner|Bikarhêner]] ([[Gotûbêja bikarhêner:Bikarhêner|gotûbêj]]) 19:19, 26 kanûna paşîn 2025 (UTC) :{{nepeyitandî}}--[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 16:09, 17 tîrmeh 2026 (UTC) {{arşîv-bin}} 4ye85ygxka3pud22hsdgs3zo65dcopz mûtesewûf 0 1358205 6291777 2026-07-28T02:10:15Z Wikihez 7344 ([[Mediawiki:Gadget-start.js|WF:NÛ]] v.2.0) +ku:navdêr: 6291777 wikitext text/x-wiki == {{ziman|ku}} == === Navdêr === {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kitêb|ku|jêgirtin=Yên wekî îbnû 'Erebî û îbnû-l Faridê jî di felsefa wehdettû-lwûcûdê da, Ji '''mûtesewûf''' û mûtefekkirên Kurdan jî, yên wekî Melayê Cizîrî, di tesewwûf û felsefa wehdetulwwûcûdê da, di edebiyata tesewwûfî da, pirr bi nav û deng û meşhûr bûne.|nivîskar=Abdurrahman Durre|sernav=Şerha Dîwana Ehmedê Xanî|weşanxane=Avesta|sal=2002|rûpel=43|isbn=975-93030-0-0}} 1dkj7kstij92seaknwmq7ankxu4f4f4 6291778 6291777 2026-07-28T02:10:38Z Wikihez 7344 /* Navdêr */ 6291778 wikitext text/x-wiki == {{ziman|ku}} == === Navdêr === {{navdêr|ku|c=mn}} # {{guharto|ku|mutesewif}} #* {{jêder-kitêb|ku|jêgirtin=Yên wekî îbnû 'Erebî û îbnû-l Faridê jî di felsefa wehdettû-lwûcûdê da, Ji '''mûtesewûf''' û mûtefekkirên Kurdan jî, yên wekî Melayê Cizîrî, di tesewwûf û felsefa wehdetulwwûcûdê da, di edebiyata tesewwûfî da, pirr bi nav û deng û meşhûr bûne.|nivîskar=Abdurrahman Durre|sernav=Şerha Dîwana Ehmedê Xanî|weşanxane=Avesta|sal=2002|rûpel=43|isbn=975-93030-0-0}} oj0kbh1krc6pvp25g8q7u8meege0l70 Gotûbêja modulê:dara kategoriyan 829 1358206 6291792 2026-07-28T02:25:16Z Wikihez 7344 [[MediaWiki:Gadget-aWa.js/belgekirin|aWa]]: Li [[Wîkîferheng:Xebat/arşîv 1#Modul:dara kategoriyan]] lînka nîqaşê ji [[Wîkîferheng:Xebat]] tê zêdekirin 6291792 wikitext text/x-wiki == Modul:dara kategoriyan == : ''Binêre [[Wîkîferheng:Xebat/arşîv 1#Modul:dara kategoriyan]].''[[Bikarhêner:Wikihez|Wikihez]] ([[Gotûbêja bikarhêner:Wikihez|gotûbêj]]) 02:25, 28 tîrmeh 2026 (UTC) rc9pvurwmfu9epqa11foj1cdj1d5ggs