Vikisöz trwikiquote https://tr.wikiquote.org/wiki/Anasayfa MediaWiki 1.39.0-wmf.23 first-letter Ortam Özel Tartışma Kullanıcı Kullanıcı mesaj Vikisöz Vikisöz tartışma Dosya Dosya tartışma MediaWiki MediaWiki tartışma Şablon Şablon tartışma Yardım Yardım tartışma Kategori Kategori tartışma TimedText TimedText talk Modül Modül tartışma Gadget Gadget talk Gadget definition Gadget definition talk Vikisöz:Deneme tahtası 4 1712 198568 198540 2022-08-10T06:32:52Z 5.176.187.91 wikitext text/x-wiki {{/Bu satırı değiştirmeden bırakın}} Seni nasıl seviyorum bir bilsen her gece içiyorum efes pilsen. 05cswcijwuizuzxaco9roij7blxio2o Vikisöz:Köy çeşmesi 4 1743 198553 198538 2022-08-09T21:20:23Z ToprakM 19785 /* vikisevgi */ wikitext text/x-wiki {{Vikisöz:Köy çeşmesi/Başlık}} == Mobil görünümdeki yazının logoya dönüştürülmesi == [[File:Wikiquote-wordmark-tr.png|thumb]] Mobildeki yazı olarak gözüken "Vikisöz" metninin [[:File:Wikiquote-wordmark-tr.png]] resmi ile değiştirilmesini teklif ediyorum. --[[Kullanıcı:ToprakM|<span style="font-family: old english text mt;color:blue;font-size:93%">'''''ToprakM'''''</span>]]&thinsp;<sup>[[Kullanıcı mesaj:ToprakM|<span style="color: #bf0023;">✉</span>]]</sup> 21.15, 21 Ağustos 2020 (UTC) :Son değişikliklerde ismini gördüklerimi etikeliyorum: {{ping|‎Felecita}} {{ping|‎Kerim Coşkun Mirzazade}} {{ping|‎Uncitoyen}} {{ping|‎Dakmor Tojira}} {{ping|‎LuCKY}} {{ping|‎Dr. Coal}} {{ping|‎Evrifaessa}} {{ping|‎DrArdeN}} --[[Kullanıcı:ToprakM|<span style="font-family: old english text mt;color:blue;font-size:93%">'''''ToprakM'''''</span>]]&thinsp;<sup>[[Kullanıcı mesaj:ToprakM|<span style="color: #bf0023;">✉</span>]]</sup> 17.17, 22 Ağustos 2020 (UTC) * {{Destek}} {{seslen|ToprakM}} hala geçerliyse bu teklif güzel olur diye düşünüyorum. ×[[Kullanıcı:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:16px;">Elvorix</span>]]<sup>[[Kullanıcı mesaj:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:13px;">mesaj</span>]]</sup> 15.43, 3 Temmuz 2021 (UTC) == Vikisöz iletişim == Herkese merhaba, diğer kardeş projelerde olduğu gibi bir telegram grubu kurmayı öneriyorum. İletişim açısından güzel olucağını ve Vikisözün aktifliğinin artıcağını düşünüyorum. Grup içerisinde "[[meta:Friendly_space_policies/tr|dostane alan politikalarının]]" geçerli olmasını teklif ediyorum. [[Vikisöz:Telegram]] sayfasından daha fazla bilgiye ulaşılabilir. Henüz grup kurulmadı çeşmede kabul görülürse hep beraber kuralım. Aktif gördüğüm kullanıcılara sesleneceğim {{seslen|Felecita|Pamfilyalı|ToprakM|Vitruvian|Turgut46}} ×[[Kullanıcı:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:16px;">Elvorix</span>]]<sup>[[Kullanıcı mesaj:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:13px;">mesaj</span>]]</sup> 10.16, 4 Ağustos 2021 (UTC) *{{Destek}} Son zamanlarda Vikigezgin vb. kardeş projelerde de yaygınlaştı Telegram kullanımı, destekliyorum. [[Kullanıcı:Pamfilyalı|Pamfilyalı]] ([[Kullanıcı mesaj:Pamfilyalı|mesaj]]) 10.18, 4 Ağustos 2021 (UTC) * Pek aktif olacağını sanmıyorum. Ancak oluşturulmasının da mahsuru yok. Ben destekliyorum. --[[Kullanıcı:ToprakM|<span style="font-family: old english text mt;color:blue;font-size:93%">'''''ToprakM'''''</span>]]&thinsp;<sup>[[Kullanıcı mesaj:ToprakM|<span style="color: #bf0023;">✉</span>]]</sup> 12.44, 4 Ağustos 2021 (UTC) * İyi fikir. Destekliyorum. - <span style="text-shadow:gray 0.1em 0.1em 0.2em; class=text">[[Kullanıcı mesaj:Felecita|<font color="black" face="Tahoma">'''F'''</font><font color="black" face="Tahoma" size="2">elecita</font>]]</span> 14.34, 4 Ağustos 2021 (UTC) * Fikir birliği oluştuğuna göre herkesi Türkçe Vikisöz telegram grubuna [https://t.me/vikisoz davet ediyorum!] ×[[Kullanıcı:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:16px;">Elvorix</span>]]<sup>[[Kullanıcı mesaj:Elvorix|<span style="color:black;font-fa family:Script MT Bold;font-size:13px;">mesaj</span>]]</sup> 15.00, 4 Ağustos 2021 (UTC) *Selamlar, iyi çalışmalar. Telegram hesabım olmadığından katılamıyorum. Güzel fikir. İleride dahil olacağım. Aktif bir duruma dönüş yapacağım. [[Kullanıcı:Vitruvian|<font color="#222000">'''Vitruvian'''</font>]] ([[Kullanıcı mesaj:Vitruvian|mesaj]]) 18.21, 8 Ağustos 2021 (UTC) == Gadget == [[w:tr:MediaWiki:Gadget-charinsert-core.js]] Türkçe Vikisöze eklense güzel olur. Şu anki sayfanın en altında, sürekli in çık uğraştırıyor. {{seslen|ToprakM}} ben oluşturamıyorum da, aktif arayüz yöneticisi sizi gördüğüm için sesleniyorum. ×[[Kullanıcı:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:16px;">Elvorix</span>]]<sup>[[Kullanıcı mesaj:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:13px;">mesaj</span>]]</sup> 14.13, 4 Ağustos 2021 (UTC) :Ekledim @[[Kullanıcı:Elvorix|Elvorix]] --[[Kullanıcı:ToprakM|<span style="font-family: old english text mt;color:blue;font-size:93%">'''''ToprakM'''''</span>]]&thinsp;<sup>[[Kullanıcı mesaj:ToprakM|<span style="color: #bf0023;">✉</span>]]</sup> 23.48, 26 Ağustos 2021 (UTC) == Günün sözü == Bir süredir günün sözünü oluşturan bot çalışmıyor ve günün sözü boş kalıyor bu konuda bir şeyler yapılmalı. ×[[Kullanıcı:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:16px;">Elvorix</span>]]<sup>[[Kullanıcı mesaj:Elvorix|<span style="color:black;font-family:Script MT Bold;font-size:13px;">mesaj</span>]]</sup> 08.19, 9 Ocak 2022 (UTC) :valla... kendimiz eklememiz lazım.. @[[Kullanıcı:Elvorix|Elvorix]], esenlikler... ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 13.50, 30 Temmuz 2022 (UTC) == Niveles ve kuklaları için küresel ban == Merhaba. Niveles ve kuklalarının küresel olarak banlanması için Meta'da bir "Request for Comment" (RfC) oluşturulmuştur. Niveles'in katkıda bulunduğu projeler arasında burası da yer aldığı için bilgilerdirilmiş bulunmaktasınız. Tartışmatı [[:m:Requests for comment/Global ban for Niveles and socks]] sayfasında bulabilirsiniz. İyi günler. [[Kullanıcı:Styyx|Styyx]] ([[Kullanıcı mesaj:Styyx|mesaj]]) 19.10, 7 Şubat 2022 (UTC) == Wiki Loves Folklore is extended till 15th March == <div lang="en" dir="ltr" class="mw-content-ltr">{{int:please-translate}} [[File:Wiki Loves Folklore Logo.svg|right|frameless|180px]] Greetings from Wiki Loves Folklore International Team, We are pleased to inform you that [[:c:Commons:Wiki Loves Folklore|Wiki Loves Folklore]] an international photographic contest on Wikimedia Commons has been extended till the '''15th of March 2022'''. The scope of the contest is focused on folk culture of different regions on categories, such as, but not limited to, folk festivals, folk dances, folk music, folk activities, etc. We would like to have your immense participation in the photographic contest to document your local Folk culture on Wikipedia. You can also help with the [[:c:Commons:Wiki Loves Folklore 2022/Translations|translation]] of project pages and share a word in your local language. Best wishes, '''International Team'''<br /> '''Wiki Loves Folklore''' [[Kullanıcı:MediaWiki message delivery|MediaWiki message delivery]] ([[Kullanıcı mesaj:MediaWiki message delivery|mesaj]]) 04.50, 22 Şubat 2022 (UTC) </div> <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=22754428 listesini kullanan Rockpeterson@metawiki --> == Coming soon == <div class="plainlinks mw-content-ltr" lang="en" dir="ltr"> === Several improvements around templates === Hello, from March 9, several improvements around templates will become available on your wiki: * Fundamental improvements of the [[Mw:Special:MyLanguage/Help:VisualEditor/User guide#Editing templates|VisualEditor template dialog]] ([[m:WMDE Technical Wishes/VisualEditor template dialog improvements|1]], [[m:WMDE Technical Wishes/Removing a template from a page using the VisualEditor|2]]), * Improvements to make it easier to put a template on a page ([[m:WMDE Technical Wishes/Finding and inserting templates|3]]) (for the template dialogs in [[Mw:Special:MyLanguage/Help:VisualEditor/User guide#Editing templates|VisualEditor]], [[Mw:Special:MyLanguage/Extension:WikiEditor#/media/File:VectorEditorBasic-en.png|2010 Wikitext]] and [[Mw:Special:MyLanguage/2017 wikitext editor|New Wikitext Mode]]), * and improvements in the syntax highlighting extension [[Mw:Special:MyLanguage/Extension:CodeMirror|CodeMirror]] ([[m:WMDE Technical Wishes/Improved Color Scheme of Syntax Highlighting|4]], [[m:WMDE Technical Wishes/Bracket Matching|5]]) (which is available on wikis with writing direction left-to-right). All these changes are part of the “[[m:WMDE Technical Wishes/Templates|Templates]]” project by [[m:WMDE Technical Wishes|WMDE Technical Wishes]]. We hope they will help you in your work, and we would love to hear your feedback on the talk pages of these projects. </div> - [[m:User:Johanna Strodt (WMDE)|Johanna Strodt (WMDE)]] 12.39, 28 Şubat 2022 (UTC) <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=WMDE_Technical_Wishes/Technical_Wishes_News_list_all_village_pumps&oldid=22907463 listesini kullanan Johanna Strodt (WMDE)@metawiki --> == Wiki Loves Folklore 2022 ends tomorrow == [[File:Wiki Loves Folklore Logo.svg|right|frameless|180px]] International photographic contest [[:c:Commons:Wiki Loves Folklore 2022| Wiki Loves Folklore 2022]] ends on 15th March 2022 23:59:59 UTC. This is the last chance of the year to upload images about local folk culture, festival, cuisine, costume, folklore etc on Wikimedia Commons. Watch out our social media handles for regular updates and declaration of Winners. ([https://www.facebook.com/WikiLovesFolklore/ Facebook] , [https://twitter.com/WikiFolklore Twitter ] , [https://www.instagram.com/wikilovesfolklore/ Instagram]) The writing competition Feminism and Folklore will run till 31st of March 2022 23:59:59 UTC. Write about your local folk tradition, women, folk festivals, folk dances, folk music, folk activities, folk games, folk cuisine, folk wear, folklore, and tradition, including ballads, folktales, fairy tales, legends, traditional song and dance, folk plays, games, seasonal events, calendar customs, folk arts, folk religion, mythology etc. on your local Wikipedia. Check if your [[:m:Feminism and Folklore 2022/Project Page|local Wikipedia is participating]] A special competition called '''Wiki Loves Falles''' is organised in Spain and the world during 15th March 2022 till 15th April 2022 to document local folk culture and [[:en:Falles|Falles]] in Valencia, Spain. Learn more about it on [[:ca:Viquiprojecte:Falles 2022|Catalan Wikipedia project page]]. We look forward for your immense co-operation. Thanks Wiki Loves Folklore international Team [[Kullanıcı:MediaWiki message delivery|MediaWiki message delivery]] ([[Kullanıcı mesaj:MediaWiki message delivery|mesaj]]) 14.40, 14 Mart 2022 (UTC) <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=Distribution_list/Global_message_delivery&oldid=22754428 listesini kullanan Rockpeterson@metawiki --> == Coming soon: Improvements for templates == <div class="plainlinks mw-content-ltr" lang="tr" dir="ltr"> <!--T:11--> [[File:Overview of changes in the VisualEditor template dialog by WMDE Technical Wishes.webm|thumb|Şablon kutusundaki temel değişiklikler.]] Merhaba! Projenize yakında şablonlarla ilgili daha fazla değişiklik gelecek: [[mw:Special:MyLanguage/Help:VisualEditor/User guide#Editing templates|Görsel Düzenleyici]]'deki ve [[mw:Special:MyLanguage/2017 wikitext editor|2017 Kaynak Düzenleyici]]'deki şablon kutusu '''temel olarak''' geliştirilecektir. Bu değişiklik(ler); şablonların amacı, şablonun nasıl görüntüleneceği ve parametrelerin nasıl ekleneceği konusunda kullanıcıların daha iyi anlamasına olanak sağlayacaktır. * Daha fazla bilgi için ilgili [[metawiki:WMDE Technical Wishes/VisualEditor template dialog improvements|proje sayfasını]] veya [[metawiki:Talk:WMDE Technical Wishes/VisualEditor template dialog improvements|tartışma sayfasını]] ziyaret edin. Kullanıcılar, söz dizimi vurgulamada ([[mw:Special:MyLanguage/Extension:CodeMirror|CodeMirror]] uzantısı), '''renk körü dostu''' adlı ayarı aktifleştirebileceklerdir. * Daha fazla bilgi için ilgili [[metawiki:WMDE Technical Wishes/Improved Color Scheme of Syntax Highlighting#Color-blind_mode|proje sayfasını]] veya [[metawiki:Talk:WMDE Technical Wishes/Improved Color Scheme of Syntax Highlighting|tartışma sayfasını]] ziyaret edin. Değişikliklerin 10 Mayıs'ta aktif bir hâle gelmesi planlanmaktadır. Bu güncelleme, [[m:WMDE Technical Wishes|WMDE Teknik]]'in [[m:WMDE Technical Wishes/Templates|şablonlar]] alanındaki son geliştirmesi kapsamındadır. Geri bildirimlerinizi ilgili tartışma sayfalarında görmeyi çok isteriz! </div> -- [[m:User:Johanna Strodt (WMDE)|Johanna Strodt (WMDE)]] 11.14, 29 Nisan 2022 (UTC) <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=WMDE_Technical_Wishes/Technical_Wishes_News_list_all_village_pumps&oldid=23222263 listesini kullanan Johanna Strodt (WMDE)@metawiki --> == <span lang="en" dir="ltr" class="mw-content-ltr">Editing news 2022 #1</span> == <div lang="en" dir="ltr" class="mw-content-ltr"> <section begin="message"/><i>[[metawiki:VisualEditor/Newsletter/2022/April|Read this in another language]] • [[m:VisualEditor/Newsletter|Subscription list for this multilingual newsletter]]</i> [[File:Junior Contributor New Topic Tool Completion Rate.png|thumb|New editors were more successful with this new tool.]] The [[mw:Special:MyLanguage/Help:DiscussionTools#New discussion tool|New topic tool]] helps editors create new ==Sections== on discussion pages. New editors are more successful with this new tool. You can [[mw:Talk pages project/New topic#21 April 2022|read the report]]. Soon, the Editing team will offer this to all editors at the 20 Wikipedias that participated in the test. You will be able to turn it off at [[Special:Preferences#mw-prefsection-editing-discussion]].<section end="message"/> </div> [[User:Whatamidoing (WMF)|Whatamidoing (WMF)]] 18.55, 2 Mayıs 2022 (UTC) <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=Global_message_delivery/Targets/VisualEditor/Newsletter/Wikis_with_VE&oldid=22019984 listesini kullanan Quiddity (WMF)@metawiki --> == Masaüstü Geliştirmeleri Hakkında == [[File:WP20Symbols MediaWiki light background.svg|200px|right]] Merhaba! Bazı wikilerin [[mw:Special:MyLanguage/Reading/Web/Desktop_Improvements|farklı masaüstü arayüzü]] olduğunu fark ettiniz mi? Sonraki adımları merak ediyor musunuz? Tasarım veya teknik konularla ilgili sorularınız veya fikirleriniz var mı? Masaüstü Geliştirmeleri üzerinde çalışan ekiple çevrimiçi bir toplantıya katılın! Zoom aracılığıyla '''17 Mayıs 2022 [https://www.timeanddate.com/worldclock/fixedtime.html?iso=20220517T1200 12:00 UTC], [https://www.timeanddate.com/worldclock/fixedtime.html?iso=20220517T1900 19:00 UTC]''' üzerinden gerçekleşecek. '''[https://wikimedia.zoom.us/j/86217494304 Katılmak için buraya basınız]'''. Toplantı kimliği: 86217494304. [https://wikimedia.zoom.us/u/k7CirSh8W Konumunuza göre arayın]. '''Konu''' * Son gelişmeler hakkında güncellemeler * Sorular, cevaplar ve tartışma '''Tarz''' Toplantı kaydedilmeyecek veya yayınlanmayacaktır. Notlar bir [https://docs.google.com/document/d/1G4tfss-JBVxyZMxGlOj5MCBhOO-0sLekquFoa2XiQb8/edit# Google Dokümanlar dosyasında] paylaşılacaktır. [[mw:User:OVasileva_(WMF)|Olga Vasileva]] (Ürün Müdürü) bu toplantıya ev sahipliği yapacak. Sunum İngilizce olarak verilecektir. İngilizce, İtalyanca, Lehçe olarak sorulan soruları yanıtlayabiliriz; ayrıca sadece ilk toplantıda: Farsça, Vietnamca; sadece ikinci toplantıda: Portekizce, İspanyolca, Rusça soruları cevaplayabiliriz. deki dillerden sorulan soruları yanıtlayabiliriz. Önceden soru sormak isterseniz sorularınızı [[mw:Talk:Reading/Web/Desktop_Improvements|tartışma sayfasına]] yazınız veya sgrabarczuk@wikimedia.org'ye gönderiniz. Bu toplantıda hem [[foundation:Friendly_space_policy|Dost alan politikası]] hem de Wikimedia teknik alanları için [[mw:Special:MyLanguage/Code_of_Conduct|Davranış Kuralları]] geçerlidir. [[foundation:Privacy_policy|WMF Gizlilik Politikası]]'na tabi değildir. Seni görmeyi umut ediyoruz! [[User:SGrabarczuk (WMF)|SGrabarczuk (WMF)]] ([[User talk:SGrabarczuk (WMF)|mesaj]]) 01.49, 17 Mayıs 2022 (UTC) <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=User:SGrabarczuk_(WMF)/sandbox/MM/Other_TOP20/tr&oldid=22381339 listesini kullanan SGrabarczuk (WMF)@metawiki --> == 5000. madde logosu == herkese esenlikler! şu an mevcut madde sayımız 4728 ve köy çeşmesinde bulunan konular ise neredeyse 1 yıl kadar eskiye gittiğinden dolayı şimdiden bu başlığı açayım diye düşündüm. 1 yıl içerisinde 5000 maddeyi geçeceğimizi umuyorum. ama vikisöz'e kim giriyor çıkıyor? yine de ben olmalı diyorum bu işe. basit bir görünüm olsa bile 5000. maddeyi kutlamak için logo koymalıyız. görüşleriniz nedir? [[Kullanıcı:Modern primat|Modern primat]] ([[Kullanıcı mesaj:Modern primat|mesaj]]) 07.40, 26 Haziran 2022 (UTC) :{{Destek}} Olabilir. Vikipedi'deki 500.000 logosu gibi. [[Kullanıcı:AxisAce09|AxisAce09]] ([[Kullanıcı mesaj:AxisAce09|mesaj]]) 20.48, 18 Temmuz 2022 (UTC) == Results of Wiki Loves Folklore 2022 is out! == <div lang="en" dir="ltr" class="mw-content-ltr"> {{int:please-translate}} [[File:Wiki Loves Folklore Logo.svg|right|150px|frameless]] Hi, Greetings The winners for '''[[c:Commons:Wiki Loves Folklore 2022|Wiki Loves Folklore 2022]]''' is announced! We are happy to share with you winning images for this year's edition. This year saw over 8,584 images represented on commons in over 92 countries. Kindly see images '''[[:c:Commons:Wiki Loves Folklore 2022/Winners|here]]''' Our profound gratitude to all the people who participated and organized local contests and photo walks for this project. We hope to have you contribute to the campaign next year. '''Thank you,''' '''Wiki Loves Folklore International Team''' --[[Kullanıcı:MediaWiki message delivery|MediaWiki message delivery]] ([[Kullanıcı mesaj:MediaWiki message delivery|mesaj]]) 16.13, 4 Temmuz 2022 (UTC) </div> <!-- Mesajı gönderen kullanıcı: https://meta.wikimedia.org/w/index.php?title=Distribution_list/Non-Technical_Village_Pumps_distribution_list&oldid=23454230 listesini kullanan Tiven2240@metawiki --> == önemli günler ve günün sözü == bence günün sözü bölümü önceden "parsellenmeli". yani çok zaman önceden o günde önemli olan neyse onun hakkında özlü söz eklenmeli. yani.. bi 50 tane önemli gün bulabiliriz bence.. gayet iyi iş olur. esenlikler.... [[Kullanıcı:Modern primat|Modern primat]] ([[Kullanıcı mesaj:Modern primat|mesaj]]) 20.51, 7 Temmuz 2022 (UTC) :temmuz-aralık arası önemli günleri bulacağım. [[Kullanıcı:Modern primat|Modern primat]] ([[Kullanıcı mesaj:Modern primat|mesaj]]) 19.24, 8 Temmuz 2022 (UTC) :en başa yazayım: bu iş, o önemli günde buraya bakanları etkileyecektir ve milletimizin vikisöze(ve diğer vikimedya projelerine?) ilgisini artıracaktır. :[https://gunisigikitapligi.com/wp-content/uploads/2018/11/GUZ-18_ONEMLI-GUNLER-DIJITAL-LINKLI.pdf buraya bakyom] , ayrıca yazayım anma ve bayram günlerini gösteriyor bu çoğunlukla. önemli olayların olduğu günleri de eklemek lazım aslında.... ve bulabildiklerimi, gördüklerimi ekledim. :siz de bu başlığa veya [[Vikisöz:Günün sözü/Arşiv|arşivdeki ilgili yerlere]] doğrudan ekleyebilirsiniz. sözleri bulmak için ise ilgili anahtar sözcükleri arama kutusunda aratmanızı tavsiye ediyorum. ve de özlü sözün kaynağı var mı diye bakmanız da lazım bence, bunun için ingilizce hâline de bakabilirsiniz. :9 temmuz için kurban bayramı ile ilgili söz ekledim bile..(umarım kabul eylenir değişikliğim, ekleme: aslında "vikisöz:" maddesi olduğu için doğrudan yayınlanıyor..) :15 temmuz için de ekledim :20 temmuz: kıbrıs harekâtının başlangıcı :24 temmuz: [[w:tr:Basın Özgürlüğü için Mücadele Günü]] :9-6 ağustos: hiroşima ve nagazaki atom bombalamaları :30 ağustos: zafer bayramı :1 eylül: [[w:tr:Dünya Barış Günü]] ayrıca ikinci dünya savaşının başladığı gün. :21 eylül: dünya alzaymır günü(maddesini bulamasam da kayda değer gibi?) :22 eylül: hobbit günü? https://en.wikipedia.org/wiki/Hobbit_Day :13 ekim: ankara'nın başkent oluşu :29 ekim: cumhuriyet bayramı :10 kasım: atatürk'ün ölümü :24 kasım: öğretmenler günü :25 aralık: noel(eklemek gerekir mi bilmem?) [[Kullanıcı:Modern primat|Modern primat]] ([[Kullanıcı mesaj:Modern primat|mesaj]]) 20.01, 8 Temmuz 2022 (UTC) :: Merhaba. Bence iyi bir fikir ve Cumhuriyet Bayramı ile Atatürk'ün ölüm günü için bunun yıllardır uygulandığını biliyorum. Ama Vikipedi'deki ilke aklıma geldi: "Türkçe Vikipedi Türk/Türkiye Vikipedisi değildir." Günün sözüne Türkiye'nin özel günlerine yönelik sözler eklenirse tarafsızlık çiğnenir mi diye düşündüm. - <span style="text-shadow:gray 0.1em 0.1em 0.2em; class=text">[[Kullanıcı mesaj:Felecita|<font color="black" face="Tahoma">'''F'''</font><font color="black" face="Tahoma" size="2">elecita</font>]]</span> 14.55, 12 Temmuz 2022 (UTC) :::"""Vikipedi ''millî ansiklopedi'' değildir :::[[w:Vikipedi:Kısayol|Kısayollar]] :::* [https://tr.wikipedia.org/w/index.php?title=Vikipedi:VND&redirect=no#MİLLÎ VP:VND#MİLLÎ] :::* [https://tr.wikipedia.org/w/index.php?title=Vikipedi:M%C4%B0LL%C3%8E&redirect=no VP:MİLLÎ] :::* [https://tr.wikipedia.org/w/index.php?title=Vikipedi:M%C4%B0LL%C4%B0&redirect=no VP:MİLLİ] :::* [https://tr.wikipedia.org/w/index.php?title=Vikipedi:Milli&redirect=no VP:Milli] :::Vikipedi [[w:Vikipedi:BTT|beş temel taşından]] biri olan [[w:Vikipedi:TBA|tarafsızlık]] politikası sebebiyle hiçbir millet veya devletin ansiklopedisi olarak '''tanımlanamaz'''. Farklı dillerde birçok Vikipedi projesi mevcuttur ve bunların hepsi aynı çatı altında birleşmektedir. Topluluklarının farklılıkları sebebiyle farklı özellikleri ve yönleri bulunsa da tüm Vikipedi projeleri temelde aynıdırlar. Farklı dillerde içerik sunmaları onları o dillerle bağdaştırılan millet veya devletlerin ansiklopedisi kılmamaktadır.""" :::amacımız burayı daha ilgi çekici yapmak olmalı. elbette burası tarafsızdır. ancak yalnızca maddelerde olan sözleri koyuyoruz. o sözler burayı milli ansiklopedi yapmaz bence. itiraz eden olursa, tartışma ile(o günün hangi millet, ülke için önemine bakmadan) sözleri değiştiririz. :::ayrıca ben aslında cumhuriyet bayramı ile atatürk için olanı diğer günlere de genişletmeyi öneriyorum @[[Kullanıcı:Felecita|Felecita]]. onlar için koyarken tarafsızlığımız bozulmuyor muydu? esenlikler..... [[Kullanıcı:Modern primat|Modern primat]] ([[Kullanıcı mesaj:Modern primat|mesaj]]) 19.40, 12 Temmuz 2022 (UTC) ::6 ağustos için mesela hiroşimaya atılan bomba günü, onla ilgili söz [https://tr.wikiquote.org/w/index.php?title=Vikis%C3%B6z:G%C3%BCn%C3%BCn_s%C3%B6z%C3%BC/2022/08/06&oldid=196213 ekledim.] böyle olmalı işte. ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 14.33, 30 Temmuz 2022 (UTC) == IP vandallar == önce durumu açıklayayım. bu: [https://imgur.com/q1tQ9Iu IP vandal hızlı sil şablonunu kaldırıyor. ve de IP vandallar onlarca değişikliği şak şak şak yapıyorlar..] şimdi de iki tane teklifimi sunayım: öncelikle, maddeye eklenen "<nowiki>{{sil}}</nowiki>"(hızlı sil) şablonu türkçe vikipedide olduğu gibi ancak bunu ekleyen ve yetkili tarafından çıkarılabilmeli. ikincisi ise, IP'lerin yalnızca günlük 5 kere düzenleme hakkı verilmesi... bu sayede hem çoğunluğu vandal olanları engelleyeceğiz, hem de kullanıcıları kayıt olmaya zorlayacağız ve bu sayede değişiklikleri takip edilebilir olacaktır. şimdi bu durum "herkesin katkıda bulunabileceği "ansiklopedi"" ifadesine ket vuruyor. ancak vandallarla savaşta bu "küçük" projelerde elimiz güçlü değil maalesef. iki buçukuncu(:D) ise, kötüye kullanım süzgeci diye bir şey var. vikipedide bele bir şey var, evet.. işte, bu bot arkadaşımız vandalları bir şekilde tespit ediyor ve vikihavayolundan bir bilet kesiyor(banlıyo😀😀🤤😜). belki de bu olmalı. ama bunu eklemek meşakkatli bir iş de olabilir? ara çözüm olarak ikincisini uygulamalıyız hemen. esenlikler.... ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 16.01, 26 Temmuz 2022 (UTC) == vikisevgi == kullanıcı mesaj sayfalarında vikisevgi gönderemiyorum?? şu anki hâli: https://imgur.com/qmlWAQD olması gereken: https://imgur.com/fEqj5EH arayüz yöneticisini çağırıyorum, esenlikler @[[Kullanıcı:ToprakM|ToprakM]]. lütfen ekliyin. ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 13.51, 2 Ağustos 2022 (UTC) :Topluluk kararıyla [[mw:Extension:WikiLove|alakalı]] eklenti eklenebilir. --[[Kullanıcı:ToprakM|<span style="font-family: old english text mt;color:blue;font-size:93%">'''''ToprakM'''''</span>]]&thinsp;<sup>[[Kullanıcı mesaj:ToprakM|<span style="color: #bf0023;">✉</span>]]</sup> 13.56, 2 Ağustos 2022 (UTC) ::eğer topluluk kararı gerektiriyorsa son değişikliklerde gördüklerimi bir çağırayım: @[[Kullanıcı:Supermæn|Supermæn]], @[[Kullanıcı:LisafBia6531|LisafBia6531]], @[[Kullanıcı:AxisAce09|AxisAce09]], @[[Kullanıcı:1980OmerYilmaz|1980OmerYilmaz]], @[[Kullanıcı:Felecita|Felecita]]. ::bence vikisevgi eklentisi olabilmeli. teşekkür olur, ödül vermek olur... gayet işe yarar bi şey bu. ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 14.09, 2 Ağustos 2022 (UTC) :::@[[Kullanıcı:Victor Trevor|Victor Trevor]] ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 14.24, 2 Ağustos 2022 (UTC) :{{destek}} [[Kullanıcı:LisafBia6531|LisafBia6531]] ([[Kullanıcı mesaj:LisafBia6531|mesaj]]) 14.43, 2 Ağustos 2022 (UTC) * Ping için teşekkürler. Bu eklentinin varsayılan olarak tüm vikilerde olduğunu sanıyordum. Eklenmemesi için hiçbir neden yok. --<span style="text-shadow: 2px 2px 4px #73C9FF; font-size: 106%;">[[Kullanıcı:Victor Trevor|<span style="color: black">Victor Trevor</span>]]</span> ([[Kullanıcı_mesaj:Victor Trevor|<span style="color: green">mesaj</span>]]) 15.04, 2 Ağustos 2022 (UTC) * {{destek}} Olması gereken bir eklenti. Önerilmesi güzel olmuş. -- [[Kullanıcı:Supermæn|Supermæn]] <small>[[Kullanıcı mesaj:Supermæn|*]]</small> 16.29, 2 Ağustos 2022 (UTC) *{{Destek}}--[[Kullanıcı:AxisAce09|AxisAce09]] ([[Kullanıcı mesaj:AxisAce09|mesaj]]) 17.41, 2 Ağustos 2022 (UTC) *{{Destek}} - <span style="text-shadow:gray 0.1em 0.1em 0.2em; class=text">[[Kullanıcı mesaj:Felecita|<font color="black" face="Tahoma">'''F'''</font><font color="black" face="Tahoma" size="2">elecita</font>]]</span> 09.34, 3 Ağustos 2022 (UTC) *:Fikir birliği var gibi gözükmekte. Phabricator'e istek gönderilebilir. [[Kullanıcı:LisafBia6531|LisafBia6531]] ([[Kullanıcı mesaj:LisafBia6531|mesaj]]) 19.08, 7 Ağustos 2022 (UTC) [[k:Victor Trevor|Victor Trevor]] [[k:ToprakM|ToprakM]] *::ve de bu tartışma bitmeden benzer bir şeyi de ekleyebilir miyiz? Şablon:PAGEBANNER eklenmeli. gerekli bilgi ve yazışma [https://tr.wikiquote.org/w/index.php?title=Kullan%C4%B1c%C4%B1_mesaj:Superyetkin&oldid=198385#%C5%9Eablon:PAGEBANNER burada] var. ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 19.26, 7 Ağustos 2022 (UTC) *::bi tane daha var, son değişikliklerde AWB değişikliklerini saklama ile ilgili.. gerekli bilgi ve yazışma [https://tr.wikiquote.org/w/index.php?title=Kullan%C4%B1c%C4%B1_mesaj:Victor_Trevor&oldid=198537 burada] var. ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 20.13, 8 Ağustos 2022 (UTC) * Başvuru yapıldı: [[phab:T314895]] --[[Kullanıcı:ToprakM|<span style="font-family: old english text mt;color:blue;font-size:93%">'''''ToprakM'''''</span>]]&thinsp;<sup>[[Kullanıcı mesaj:ToprakM|<span style="color: #bf0023;">✉</span>]]</sup> 21.20, 9 Ağustos 2022 (UTC) e0ugrwj6vkq3ogt5tkbqo49svg5ewkw Sonsuzluk 0 6435 198569 198488 2022-08-10T11:29:14Z Victor Trevor 26420 wikitext text/x-wiki * Burası ve şimdiki an sonsuzluktur. — [[Erich Fromm]] * Sadece iki şey sonsuzdur, evren ve insan ahmaklığı, ilkinden o kadar da emin değilim. — [[Albert Einstein]] * Felsefe, mekanı boşluk, hedefi sonsuzluk olan, bir bilgi serüvenidir. — [[Yalçın Küçük]] * İnsan aklı sonsuza yatkındır.İnsan yürüyüşü sonsuza yöneliktir.Sonsuza bakmayan her yürüyüş tökezlemeye ve düşmeye mahkumdur. — [[Yalçın Küçük]] * Sonsuzluk yolunda nasıl böylesine kolayca ilerlediğine hayret eden birisi vardı; gerçekte hızla bayır aşağı yuvarlanıyordu. — [[Franz Kafka]] {{Vikiler| commons= | wikispecies= | wikt= | b= | s= | w= {{PAGENAME}} | n= | m= | }} {{Vikisöz bağlantıları}} [[Kategori:Konular]] trl9biuo6gykn029xoefahrflwemnx2 PKK 0 7960 198556 198478 2022-08-09T21:27:54Z ToprakM 19785 wikitext text/x-wiki {{Biyografi}} '''PKK'''; 1978'den beri ortadoğuda faaliyet gösteren, pek çok ülke tarafından yasadışı olarak görülen, askerî/sivil hedeflere saldıran ve Türkiye, İran, Irak ve Suriye'nin içinde bulunduğu bölgede bir devlet kurma amacının olduğu silahlı örgüttür. == Hakkında söylenenler == *Eğer bizim yürüttüğümüz silahlı mücadelenin özelliklerini kavrasaydınız müthiş kazandırdığını görecektiniz. Silahlı mücadele yalnızca silahların patlaması değildir, en yüksek ideolojik yoğunlaşmaktır bana göre. Politikayı en gerçekçi kavrayıştır. Bana göre silahlı mücadeleden bahsediyorum, sizin veya başkalarının kavradığı biçimde değil. Ve her hâlde bu biraz daha Kürtler için böyledir. Onları tek adam edecek... Biraz... Bu araçtan başka bir gelişme yolunun kendilerine tanınmamasından ileri geliyor, niye anlamıyorsunuz?<ref>https://www.youtube.com/watch?v=iJ91JxQJt44&t=523s</ref> — [[Abdullah Öcalan]] *Hepsi bizim. Öldükleri andan itibaren bizim. Atatürk nasıl ki Çanakkale’de, Anzaklar geldiği zaman diyor ki, artık onlar bizim de evlatlarımızdır. Onların anne babaları da bizim vatandaşımız. Çocukları kandırılmış, gitmiş. Sonunda da bedelini canıyla ödemişler. Onlar artık bizim şehitlerimiz... Veyahut da bizim ölülerimiz. Ama sonuçta bizim evlatlarımız kandırılıp PKK’lı yapıldı... ” — [[Mehmet Gül]] - Eski MHP Milletvekili<ref>[http://www.aktifhaber.com/news_detail.php?id=142411 aktif haber][http://www.ensonhaber.com/Gundem/95406/Olay-roportajin-teyp-kayitlari.html enson haber]</ref> *Bu adama haddi bildirilmelidir. Kedisini bile vermezmiş... Kürt, bizim kardeşimiz, soydaşımız, candaşımız. Kürdün kedisi de, keçisi de, kendisi de Türk milleti için değerlidir. Barzani'den bizim isteğimiz, kedi değildir, PKK elebaşlarıdır. Türkiye yıllarca (...) Barzani’yi kucağına oturtup sakalını yoldurmuştur. — [[Muhsin Yazıcıoğlu]] - ''Barzani hakkındaki yorumu'' *Kan döken insanlar "biz kan dökmekten vazgeçtik" derlerse, "iyi yaptınız, alın size bir mükâfat verelim" denmesi mümkün değil. Kan döken insanlara "aman vazgeçmeyin, kan dökmeye devam edin" demek de mümkün değil. Kan döken insanlar bundan vazgeçerlerse, "bu iyi olmadı" demek de mümkün değil.<ref>{{web kaynağı|url = http://www.milliyet.com.tr/demirel-in-unutulmayan-sozleri-gundem-2075042/ |başlık= Demirel'in unutulmayan sözleri |yayıncı= Milliyet Gazeresi |erişimtarihi= 15 Eylül 2015}}</ref> — [[Süleyman Demirel]] == Kaynakça == {{Kaynakça}} {{Vikiler| commons= | wikispecies= | wikt= | b= | s= | w= Kürdistan İşçi Partisi | n= | m= | }} {{Vikisöz bağlantıları}} {{taslak}} [[Kategori:Konular]] 6tq99txmxryp8r0kq5wcgfypeaz1zzt 198557 198556 2022-08-09T21:28:11Z ToprakM 19785 kişi maddesi değil wikitext text/x-wiki '''PKK'''; 1978'den beri ortadoğuda faaliyet gösteren, pek çok ülke tarafından yasadışı olarak görülen, askerî/sivil hedeflere saldıran ve Türkiye, İran, Irak ve Suriye'nin içinde bulunduğu bölgede bir devlet kurma amacının olduğu silahlı örgüttür. == Hakkında söylenenler == *Eğer bizim yürüttüğümüz silahlı mücadelenin özelliklerini kavrasaydınız müthiş kazandırdığını görecektiniz. Silahlı mücadele yalnızca silahların patlaması değildir, en yüksek ideolojik yoğunlaşmaktır bana göre. Politikayı en gerçekçi kavrayıştır. Bana göre silahlı mücadeleden bahsediyorum, sizin veya başkalarının kavradığı biçimde değil. Ve her hâlde bu biraz daha Kürtler için böyledir. Onları tek adam edecek... Biraz... Bu araçtan başka bir gelişme yolunun kendilerine tanınmamasından ileri geliyor, niye anlamıyorsunuz?<ref>https://www.youtube.com/watch?v=iJ91JxQJt44&t=523s</ref> — [[Abdullah Öcalan]] *Hepsi bizim. Öldükleri andan itibaren bizim. Atatürk nasıl ki Çanakkale’de, Anzaklar geldiği zaman diyor ki, artık onlar bizim de evlatlarımızdır. Onların anne babaları da bizim vatandaşımız. Çocukları kandırılmış, gitmiş. Sonunda da bedelini canıyla ödemişler. Onlar artık bizim şehitlerimiz... Veyahut da bizim ölülerimiz. Ama sonuçta bizim evlatlarımız kandırılıp PKK’lı yapıldı... ” — [[Mehmet Gül]] - Eski MHP Milletvekili<ref>[http://www.aktifhaber.com/news_detail.php?id=142411 aktif haber][http://www.ensonhaber.com/Gundem/95406/Olay-roportajin-teyp-kayitlari.html enson haber]</ref> *Bu adama haddi bildirilmelidir. Kedisini bile vermezmiş... Kürt, bizim kardeşimiz, soydaşımız, candaşımız. Kürdün kedisi de, keçisi de, kendisi de Türk milleti için değerlidir. Barzani'den bizim isteğimiz, kedi değildir, PKK elebaşlarıdır. Türkiye yıllarca (...) Barzani’yi kucağına oturtup sakalını yoldurmuştur. — [[Muhsin Yazıcıoğlu]] - ''Barzani hakkındaki yorumu'' *Kan döken insanlar "biz kan dökmekten vazgeçtik" derlerse, "iyi yaptınız, alın size bir mükâfat verelim" denmesi mümkün değil. Kan döken insanlara "aman vazgeçmeyin, kan dökmeye devam edin" demek de mümkün değil. Kan döken insanlar bundan vazgeçerlerse, "bu iyi olmadı" demek de mümkün değil.<ref>{{web kaynağı|url = http://www.milliyet.com.tr/demirel-in-unutulmayan-sozleri-gundem-2075042/ |başlık= Demirel'in unutulmayan sözleri |yayıncı= Milliyet Gazeresi |erişimtarihi= 15 Eylül 2015}}</ref> — [[Süleyman Demirel]] == Kaynakça == {{Kaynakça}} {{Vikiler| commons= | wikispecies= | wikt= | b= | s= | w= Kürdistan İşçi Partisi | n= | m= | }} {{Vikisöz bağlantıları}} {{taslak}} [[Kategori:Konular]] 3hfp7m0f185wtumr1oebh3y5jzfpnyl MediaWiki:Gadgets-definition 8 18070 198564 181451 2022-08-09T21:33:37Z ToprakM 19785 wikitext text/x-wiki == Genel == * HizliBilgi[ResourceLoader|default]|HizliBilgi.js * Gezinti_pencereleri[ResourceLoader]|popups.js * HotCat[ResourceLoader|rights=edit|default]|HotCat.js * UTCLiveClock[ResourceLoader]|UTCLiveClock.js * Cat-a-lot[ResourceLoader|rights=edit|dependencies=mediawiki.util]|Cat-a-lot.js * PratikMenu[ResourceLoader|dependencies=mediawiki.api,mediawiki.util,user.options|peers=PratikMenu-pagestyles]|PratikMenu.js * PratikMenu-pagestyles[hidden]|PratikMenu-pagestyles.css * Twinkle[ResourceLoader|rights=autoconfirmed|dependencies=ext.gadget.morebits,ext.gadget.select2,mediawiki.api,mediawiki.language|rights=autoconfirmed|type=general|peers=Twinkle-pagestyles]|Twinkle.js|Twinkle.css|twinklearv.js|twinklewarn.js|twinkleblock.js|friendlywelcome.js|friendlyshared.js|friendlytalkback.js|twinklespeedy.js|twinkleprod.js|twinklexfd.js|twinkleimage.js|twinkleprotect.js|friendlytag.js|twinklediff.js|twinkleunlink.js|twinklefluff.js|twinkledeprod.js|twinklebatchdelete.js|twinklerevdel.js|twinklebatchprotect.js|twinklebatchundelete.js|twinkleconfig.js * morebits[ResourceLoader|dependencies=mediawiki.user,mediawiki.util,mediawiki.Title,jquery.ui|hidden]|morebits.js|morebits.css * Twinkle-pagestyles[hidden|skins=vector,vector-2022]|Twinkle-pagestyles.css * select2[ResourceLoader|hidden]|select2.min.js|select2.min.css * BosOzet[ResourceLoader|rights=edit]|BosOzet.js|BosOzet.css * BDK[ResourceLoader|rights=review]|BekleyenDeğişiklikler.js * Kisayol[ResourceLoader]|Kisayol.js * Gerekceyardimcisi[ResourceLoader|default|rights=review]|Gerekceyardimcisi.js * GirisDegistirme[ResourceLoader|rights=edit|dependencies=mediawiki.util]|GirisDegistirme.js * XTools-MaddeBilgisi[ResourceLoader]|XTools-ArticleInfo.js * WikidataInfo [ResourceLoader|dependencies=mediawiki.jqueryMsg] | WikidataInfo.js * Wdsearch[ResourceLoader]|Wdsearch.js * ReferenceTooltips[ResourceLoader|type=general|dependencies=mediawiki.cookie,jquery.client]|ReferenceTooltips.js|ReferenceTooltips.css * charinsert[ResourceLoader]|charinsert.js * charinsert-core[ResourceLoader|hidden|dependencies=jquery.textSelection,user,mediawiki.storage]|charinsert-styles.css|charinsert-core.js == Hizmetliler == * Silme[ResourceLoader|rights=delete]|Silme.js * Haklar[ResourceLoader|dependencies=mediawiki.util]|Haklar.js * SurumGizleyici[ResourceLoader|rights=deleterevision]|SurumGizleyici.js 74j4kosgeicwgyko6hukd7opjznj3cz Vikisöz:Değişiklik sayılarına göre kullanıcılar listesi 4 24934 198558 198539 2022-08-09T21:30:25Z YBot 18235 Güncelleme wikitext text/x-wiki {{/begin}} <center> {| class="wikitable" ! # ! Kullanıcı ! Değişiklik sayısı ! Kullanıcı grupları |- | 1 | [[Kullanıcı:Vitruvian|Vitruvian]] | align="center" | 13.187 | editör, hizmetli |- | 2 | [[Kullanıcı:Victor Trevor|Victor Trevor]] | align="center" | 10.291 | editör |- | 3 | [[Kullanıcı:Nosferatü|Nosferatü]] | align="center" | 8.679 | editör |- | 4 | [[Kullanıcı:Felecita|Felecita]] | align="center" | 7.328 | editör, hizmetli |- | 5 | [[Kullanıcı:ToprakM|ToprakM]] | align="center" | 7.035 | editör, arayüz yöneticisi, hizmetli |- | 6 | [[Kullanıcı:Nanahuatl|Nanahuatl]] | align="center" | 4.453 | editör |- | 7 | [[Kullanıcı:Turgut46|Turgut46]] | align="center" | 4.128 | editör |- | 8 | [[Kullanıcı:Babatolian|Babatolian]] | align="center" | 3.527 | editör |- | 9 | [[Kullanıcı:Feyyaztiftik|Feyyaztiftik]] | align="center" | 3.254 | editör |- | 10 | [[Kullanıcı:AnankeBot|AnankeBot]] | align="center" | 2.796 | |- | 11 | [[Kullanıcı:Fuzûlî|Fuzûlî]] | align="center" | 2.588 | |- | 12 | [[Kullanıcı:Tarih|Tarih]] | align="center" | 2.548 | |- | 13 | [[Kullanıcı:YBot|YBot]] | align="center" | 2.419 | |- | 14 | [[Kullanıcı:Mavrikant|Mavrikant]] | align="center" | 2.078 | editör |- | 15 | [[Kullanıcı:ChtitBot|ChtitBot]] | align="center" | 2.046 | |- | 16 | [[Kullanıcı:Viki|Viki]] | align="center" | 1.972 | |- | 17 | [[Kullanıcı:Berrram|Berrram]] | align="center" | 1.959 | editör, hizmetli |- | 18 | [[Kullanıcı:Evrifaessa|Evrifaessa]] | align="center" | 1.784 | editör, arayüz yöneticisi |- | 19 | [[Kullanıcı:HakanIST|HakanIST]] | align="center" | 1.751 | editör |- | 20 | [[Kullanıcı:Kibele|Kibele]] | align="center" | 1.588 | editör |- | 21 | [[Kullanıcı:Yusuf kayadüğün|Yusuf kayadüğün]] | align="center" | 1.549 | |- | 22 | [[Kullanıcı:Dabeon|Dabeon]] | align="center" | 1.446 | editör |- | 23 | [[Kullanıcı:Science|Science]] | align="center" | 1.397 | editör |- | 24 | [[Kullanıcı:Cekli829|Cekli829]] | align="center" | 1.385 | editör |- | 25 | [[Kullanıcı:Vito Genovese|Vito Genovese]] | align="center" | 1.346 | editör |- | 26 | [[Kullanıcı:New user message|New user message]] | align="center" | 1.324 | |- | 27 | [[Kullanıcı:Dexbot|Dexbot]] | align="center" | 1.052 | |- | 28 | [[Kullanıcı:II. Niveles|II. Niveles]] | align="center" | 1.042 | |- | 29 | [[Kullanıcı:Aguzer|Aguzer]] | align="center" | 986 | |- | 30 | [[Kullanıcı:Diyapazon|Diyapazon]] | align="center" | 960 | editör |- | 31 | [[Kullanıcı:SamoaBot|SamoaBot]] | align="center" | 930 | |- | 32 | [[Kullanıcı:EleferenBot|EleferenBot]] | align="center" | 900 | |- | 33 | [[Kullanıcı:CommonsDelinker|CommonsDelinker]] | align="center" | 809 | editör |- | 34 | [[Kullanıcı:Sabri76|Sabri76]] | align="center" | 787 | editör |- | 35 | [[Kullanıcı:Ayshe17|Ayshe17]] | align="center" | 761 | |- | 36 | [[Kullanıcı:Uncitoyen|Uncitoyen]] | align="center" | 753 | editör |- | 37 | [[Kullanıcı:Reality006|Reality006]] | align="center" | 669 | |- | 38 | [[Kullanıcı:MerlIwBot|MerlIwBot]] | align="center" | 605 | |- | 39 | [[Kullanıcı:3210|3210]] | align="center" | 589 | |- | 40 | [[Kullanıcı:By erdo can|By erdo can]] | align="center" | 523 | editör |- | 41 | [[Kullanıcı:Pivox|Pivox]] | align="center" | 522 | editör |- | 42 | [[Kullanıcı:Elvorix|Elvorix]] | align="center" | 504 | editör |- | 43 | [[Kullanıcı:Modern primat|Modern primat]] | align="center" | 501 | |- | 44 | [[Kullanıcı:YiFeiBot|YiFeiBot]] | align="center" | 474 | |- | 45 | [[Kullanıcı:Pinar|Pinar]] | align="center" | 446 | editör |- | 46 | [[Kullanıcı:Amfetamin|Amfetamin]] | align="center" | 439 | |- | 47 | [[Kullanıcı:KamikazeBot|KamikazeBot]] | align="center" | 414 | |- | 48 | [[Kullanıcı:Henrymorgan92|Henrymorgan92]] | align="center" | 396 | , editör |- | 49 | [[Kullanıcı:Pathoschild|Pathoschild]] | align="center" | 392 | |- | 50 | [[Kullanıcı:Supermæn|Supermæn]] | align="center" | 391 | editör |- | 51 | [[Kullanıcı:Kendim~trwikiquote|Kendim~trwikiquote]] | align="center" | 390 | |- | 52 | [[Kullanıcı:DrArdeN|DrArdeN]] | align="center" | 390 | editör |- | 53 | [[Kullanıcı:Tragic Kingdom|Tragic Kingdom]] | align="center" | 389 | editör |- | 54 | [[Kullanıcı:Dbl2010|Dbl2010]] | align="center" | 385 | |- | 55 | [[Kullanıcı:Placeboizm|Placeboizm]] | align="center" | 374 | editör |- | 56 | [[Kullanıcı:Zaitsév|Zaitsév]] | align="center" | 352 | editör |- | 57 | [[Kullanıcı:Fzelen06|Fzelen06]] | align="center" | 331 | |- | 58 | [[Kullanıcı:Kutsalyolcusu|Kutsalyolcusu]] | align="center" | 330 | editör |- | 59 | [[Kullanıcı:Slayerized|Slayerized]] | align="center" | 325 | |- | 60 | [[Kullanıcı:Therou|Therou]] | align="center" | 311 | editör |- | 61 | [[Kullanıcı:Melinoë|Melinoë]] | align="center" | 303 | editör |- | 62 | [[Kullanıcı:1980OmerYilmaz|1980OmerYilmaz]] | align="center" | 299 | |- | 63 | [[Kullanıcı:Suelnur|Suelnur]] | align="center" | 295 | |- | 64 | [[Kullanıcı:Koc61|Koc61]] | align="center" | 262 | |- | 65 | [[Kullanıcı:VolkovBot|VolkovBot]] | align="center" | 248 | |- | 66 | [[Kullanıcı:Merube 89|Merube 89]] | align="center" | 244 | |- | 67 | [[Kullanıcı:Egemensen~trwikiquote|Egemensen~trwikiquote]] | align="center" | 238 | |- | 68 | [[Kullanıcı:Refrenantem|Refrenantem]] | align="center" | 237 | |- | 69 | [[Kullanıcı:Tegel|Tegel]] | align="center" | 232 | |- | 70 | [[Kullanıcı:Gnosis58|Gnosis58]] | align="center" | 230 | |- | 71 | [[Kullanıcı:Gökhan|Gökhan]] | align="center" | 221 | |- | 72 | [[Kullanıcı:阿尔达|阿尔达]] | align="center" | 218 | |- | 73 | [[Kullanıcı:Sinestik|Sinestik]] | align="center" | 214 | editör |- | 74 | [[Kullanıcı:Sae1962|Sae1962]] | align="center" | 212 | editör |- | 75 | [[Kullanıcı:Mutlutopuz|Mutlutopuz]] | align="center" | 210 | editör |- | 76 | [[Kullanıcı:LaaknorBot|LaaknorBot]] | align="center" | 200 | |- | 77 | [[Kullanıcı:Duvardakiyazi|Duvardakiyazi]] | align="center" | 198 | |- | 78 | [[Kullanıcı:Idioma-bot|Idioma-bot]] | align="center" | 196 | |- | 79 | [[Kullanıcı:07|07]] | align="center" | 186 | editör |- | 80 | [[Kullanıcı:Dbilgener|Dbilgener]] | align="center" | 177 | |- | 81 | [[Kullanıcı:タチコマ robot|タチコマ robot]] | align="center" | 171 | |- | 82 | [[Kullanıcı:Dakmor Tojira|Dakmor Tojira]] | align="center" | 164 | editör |- | 83 | [[Kullanıcı:Thomas|Thomas]] | align="center" | 163 | |- | 84 | [[Kullanıcı:Fatih.cyd|Fatih.cyd]] | align="center" | 151 | |- | 85 | [[Kullanıcı:Hazan|Hazan]] | align="center" | 149 | editör |- | 86 | [[Kullanıcı:Mereyü|Mereyü]] | align="center" | 148 | editör |- | 87 | [[Kullanıcı:Türkolog1984|Türkolog1984]] | align="center" | 146 | |- | 88 | [[Kullanıcı:ArthurBot|ArthurBot]] | align="center" | 132 | |- | 89 | [[Kullanıcı:Urungu97|Urungu97]] | align="center" | 129 | editör |- | 90 | [[Kullanıcı:Alaattin savas|Alaattin savas]] | align="center" | 120 | |- | 91 | [[Kullanıcı:Matiia|Matiia]] | align="center" | 115 | |- | 92 | [[Kullanıcı:Vilho-Veli|Vilho-Veli]] | align="center" | 115 | |- | 93 | [[Kullanıcı:Rəşid Nurməmmədov|Rəşid Nurməmmədov]] | align="center" | 114 | |- | 94 | [[Kullanıcı:Emperyan|Emperyan]] | align="center" | 113 | editör |- | 95 | [[Kullanıcı:Anabasis1944|Anabasis1944]] | align="center" | 111 | |- | 96 | [[Kullanıcı:CarsracBot|CarsracBot]] | align="center" | 103 | |- | 97 | [[Kullanıcı:Baylan|Baylan]] | align="center" | 102 | |- | 98 | [[Kullanıcı:Yozer1|Yozer1]] | align="center" | 102 | |- | 99 | [[Kullanıcı:Risto hot sir|Risto hot sir]] | align="center" | 101 | |- | 100 | [[Kullanıcı:Bermanya|Bermanya]] | align="center" | 100 | editör |} </center> gkqatd3eso4ti835yv6urhxje6js1hb Şablon:Ek kaynak gerekli 10 28368 198555 174295 2022-08-09T21:27:20Z ToprakM 19785 wikitext text/x-wiki {{ambox | ad = Wikify | subst = <includeonly>{{subst:substcheck}}</includeonly> | tür = içerik | sınıf = ambox-Unreferenced | resim = [[Dosya:Question_book-new.svg|50px|link=|alt=]] | sorun = '''Bu maddedeki bazı sözlerin doğrulanabilmesi için ek kaynaklara ihtiyacı vardır.''' Ayrıntılı bilgiyi maddenin [[Tartışma:{{PAGENAME}}|tartışma sayfasında]] bulabilirsiniz. | düzeltme = Maddeyi [[Vikisöz:Güvenilir kaynaklar|güvenilir kaynaklar]] ile [{{fullurl:{{FULLPAGENAME}}|action=edit}} düzenleyerek] Vikisöz'e katkıda bulunabilirsiniz. | date = {{{tarih|{{{date|{{{1|}}}}}}}}} | tarih = {{{tarih|{{{date|{{{1|}}}}}}}}} | bilgi = | cat = Ek kaynaklar gereken maddeler }}<noinclude> {{belgeleme}} [[Kategori:Uyarı şablonları]] </noinclude> 0j9akjcvjufhp5pcsqpnm4seg5w6lf3 MediaWiki:Gadget-morebits.js 8 29366 198560 168204 2022-08-09T21:31:13Z ToprakM 19785 javascript text/javascript // <nowiki> /** * A library full of lots of goodness for user scripts on MediaWiki wikis, including Wikipedia. * * The highlights include: * - {@link Morebits.wiki.api} - make calls to the MediaWiki API * - {@link Morebits.wiki.page} - modify pages on the wiki (edit, revert, delete, etc.) * - {@link Morebits.date} - enhanced date object processing, sort of a light moment.js * - {@link Morebits.quickForm} - generate quick HTML forms on the fly * - {@link Morebits.simpleWindow} - a wrapper for jQuery UI Dialog with a custom look and extra features * - {@link Morebits.status} - a rough-and-ready status message displayer, used by the Morebits.wiki classes * - {@link Morebits.wikitext} - utilities for dealing with wikitext * - {@link Morebits.string} - utilities for manipulating strings * - {@link Morebits.array} - utilities for manipulating arrays * - {@link Morebits.ip} - utilities to help process IP addresses * * Dependencies: * - The whole thing relies on jQuery. But most wikis should provide this by default. * - {@link Morebits.quickForm}, {@link Morebits.simpleWindow}, and {@link Morebits.status} rely on the "morebits.css" file for their styling. * - {@link Morebits.simpleWindow} and {@link Morebits.quickForm} tooltips rely on jQuery UI Dialog (from ResourceLoader module name 'jquery.ui'). * - To create a gadget based on morebits.js, use this syntax in MediaWiki:Gadgets-definition: * - `*GadgetName[ResourceLoader|dependencies=mediawiki.user,mediawiki.util,mediawiki.Title,jquery.ui]|morebits.js|morebits.css|GadgetName.js` * - Alternatively, you can configure morebits.js as a hidden gadget in MediaWiki:Gadgets-definition: * - `*morebits[ResourceLoader|dependencies=mediawiki.user,mediawiki.util,mediawiki.Title,jquery.ui|hidden]|morebits.js|morebits.css` * and then load ext.gadget.morebits as one of the dependencies for the new gadget. * * All the stuff here works on all browsers for which MediaWiki provides JavaScript support. * * This library is maintained by the maintainers of Twinkle. * For queries, suggestions, help, etc., head to [Wikipedia talk:Twinkle on English Wikipedia](http://en.wikipedia.org/wiki/WT:TW). * The latest development source is available at {@link https://github.com/wikimedia-gadgets/twinkle/blob/master/morebits.js|GitHub}. * * @namespace Morebits */ (function (window, document, $) { // Wrap entire file with anonymous function /** @lends Morebits */ var Morebits = {}; window.Morebits = Morebits; // allow global access /** * i18n support for strings in Morebits */ Morebits.i18n = { parser: null, /** * Set an i18n library to use with Morebits. * Examples: * Use jquery-i18n: * Morebits.i18n.setParser({ get: $.i18n }); * Use banana-i18n or orange-i18n: * var banana = new Banana('en'); * Morebits.i18n.setParser({ get: banana.i18n }); * @param {Object} parser */ setParser: function(parser) { if (!parser || typeof parser.get !== 'function') { throw new Error('Morebits.i18n: parser must implement get()'); } Morebits.i18n.parser = parser; }, /** * @private * @returns {string} */ getMessage: function () { var args = Array.prototype.slice.call(arguments); // array of size `n` // 1st arg: message name // 2nd to (n-1)th arg: message parameters // nth arg: legacy English fallback var msgName = args[0]; var fallback = args[args.length - 1]; if (!Morebits.i18n.parser) { return fallback; } // i18n libraries are generally invoked with variable number of arguments // as msg(msgName, ...parameters) var i18nMessage = Morebits.i18n.parser.get.apply(null, args.slice(0, -1)); // if no i18n message exists, i18n libraries generally give back the message name if (i18nMessage === msgName) { return fallback; } return i18nMessage; } }; // shortcut var msg = Morebits.i18n.getMessage; /** * Wiki-specific configurations for Morebits */ Morebits.l10n = { /** * Local aliases for "redirect" magic word. * Check using api.php?action=query&format=json&meta=siteinfo&formatversion=2&siprop=magicwords */ redirectTagAliases: ['#REDIRECT'], /** * Takes a string as argument and checks if it is a timestamp or not * If not, it returns null. If yes, it returns an array of integers * in the format [year, month, date, hour, minute, second] * which can be passed to Date.UTC() * @param {string} str * @returns {number[] | null} */ signatureTimestampFormat: function (str) { // HH:mm, DD Month YYYY (UTC) var rgx = /(\d{2}):(\d{2}), (\d{1,2}) (\w+) (\d{4}) \(UTC\)/; var match = rgx.exec(str); if (!match) { return null; } var month = Morebits.date.localeData.months.indexOf(match[4]); if (month === -1) { return null; } // ..... year ... month .. date ... hour .... minute return [match[5], month, match[3], match[1], match[2]]; } }; /** * Simple helper function to see what groups a user might belong. * * @param {string} group - e.g. `sysop`, `extendedconfirmed`, etc. * @returns {boolean} */ Morebits.userIsInGroup = function (group) { return mw.config.get('wgUserGroups').indexOf(group) !== -1; }; /** Hardcodes whether the user is a sysop, used a lot. * * @type {boolean} */ Morebits.userIsSysop = Morebits.userIsInGroup('sysop'); /** * Deprecated as of February 2021, use {@link Morebits.ip.sanitizeIPv6}. * * @deprecated Use {@link Morebits.ip.sanitizeIPv6}. * Converts an IPv6 address to the canonical form stored and used by MediaWiki. * JavaScript translation of the {@link https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/8eb6ac3e84ea3312d391ca96c12c49e3ad0753bb/includes/utils/IP.php#131|`IP::sanitizeIP()`} * function from the IPUtils library. Addresses are verbose, uppercase, * normalized, and expanded to 8 words. * * @param {string} address - The IPv6 address, with or without CIDR. * @returns {string} */ Morebits.sanitizeIPv6 = function (address) { console.warn('NOT: Morebits.sanitizeIPv6 Şubat 2021\'de Morebits.ip.sanitizeIPv6 olarak yeniden adlandırıldı, lütfen bunu kullanın'); // eslint-disable-line no-console return Morebits.ip.sanitizeIPv6(address); }; /** * Determines whether the current page is a redirect or soft redirect. Fails * to detect soft redirects on edit, history, etc. pages. Will attempt to * detect Module:RfD, with the same failure points. * * @returns {boolean} */ Morebits.isPageRedirect = function() { return !!(mw.config.get('wgIsRedirect') || document.getElementById('softredirect') || $('.box-RfD').length); }; /** * Stores a normalized (underscores converted to spaces) version of the * `wgPageName` variable. * * @type {string} */ Morebits.pageNameNorm = mw.config.get('wgPageName').replace(/_/g, ' '); /** * Create a string for use in regex matching a page name. Accounts for * leading character's capitalization, underscores as spaces, and special * characters being escaped. See also {@link Morebits.namespaceRegex}. * * @param {string} pageName - Page name without namespace. * @returns {string} - For a page name `Foo bar`, returns the string `[Ff]oo[_ ]bar`. */ Morebits.pageNameRegex = function(pageName) { if (pageName === '') { return ''; } var firstChar = pageName[0], remainder = Morebits.string.escapeRegExp(pageName.slice(1)); if (mw.Title.phpCharToUpper(firstChar) !== firstChar.toLowerCase()) { return '[' + mw.Title.phpCharToUpper(firstChar) + firstChar.toLowerCase() + ']' + remainder; } return Morebits.string.escapeRegExp(firstChar) + remainder; }; /** * Converts string or array of DOM nodes into an HTML fragment. * Wikilink syntax (`[[...]]`) is transformed into HTML anchor. * Used in Morebits.quickForm and Morebits.status * @internal * @param {string|Node|(string|Node)[]} input * @returns {DocumentFragment} */ Morebits.createHtml = function(input) { var fragment = document.createDocumentFragment(); if (!input) { return fragment; } if (!Array.isArray(input)) { input = [ input ]; } for (var i = 0; i < input.length; ++i) { if (input[i] instanceof Node) { fragment.appendChild(input[i]); } else { $.parseHTML(Morebits.createHtml.renderWikilinks(input[i])).forEach(function(node) { fragment.appendChild(node); }); } } return fragment; }; /** * Converts wikilinks to HTML anchor tags. * @param text * @returns {*} */ Morebits.createHtml.renderWikilinks = function (text) { var ub = new Morebits.unbinder(text); // Don't convert wikilinks within code tags as they're used for displaying wiki-code ub.unbind('<code>', '</code>'); ub.content = ub.content.replace( /\[\[:?(?:([^|\]]+?)\|)?([^\]|]+?)\]\]/g, function(_, target, text) { if (!target) { target = text; } return '<a target="_blank" href="' + mw.util.getUrl(target) + '" title="' + target.replace(/"/g, '&#34;') + '">' + text + '</a>'; }); return ub.rebind(); }; /** * Create a string for use in regex matching all namespace aliases, regardless * of the capitalization and underscores/spaces. Doesn't include the optional * leading `:`, but if there's more than one item, wraps the list in a * non-capturing group. This means you can do `Morebits.namespaceRegex([4]) + * ':' + Morebits.pageNameRegex('Twinkle')` to match a full page. Uses * {@link Morebits.pageNameRegex}. * * @param {number[]} namespaces - Array of namespace numbers. Unused/invalid * namespace numbers are silently discarded. * @example * // returns '(?:[Ff][Ii][Ll][Ee]|[Ii][Mm][Aa][Gg][Ee])' * Morebits.namespaceRegex([6]) * @returns {string} - Regex-suitable string of all namespace aliases. */ Morebits.namespaceRegex = function(namespaces) { if (!Array.isArray(namespaces)) { namespaces = [namespaces]; } var aliases = [], regex; $.each(mw.config.get('wgNamespaceIds'), function(name, number) { if (namespaces.indexOf(number) !== -1) { // Namespaces are completely agnostic as to case, // and a regex string is more useful/compatible than a RegExp object, // so we accept any casing for any letter. aliases.push(name.split('').map(function(char) { return Morebits.pageNameRegex(char); }).join('')); } }); switch (aliases.length) { case 0: regex = ''; break; case 1: regex = aliases[0]; break; default: regex = '(?:' + aliases.join('|') + ')'; break; } return regex; }; /* **************** Morebits.quickForm **************** */ /** * Creation of simple and standard forms without much specific coding. * * @namespace Morebits.quickForm * @memberof Morebits * @class * @param {event} event - Function to execute when form is submitted. * @param {string} [eventType=submit] - Type of the event. */ Morebits.quickForm = function QuickForm(event, eventType) { this.root = new Morebits.quickForm.element({ type: 'form', event: event, eventType: eventType }); }; /** * Renders the HTML output of the quickForm. * * @memberof Morebits.quickForm * @returns {HTMLElement} */ Morebits.quickForm.prototype.render = function QuickFormRender() { var ret = this.root.render(); ret.names = {}; return ret; }; /** * Append element to the form. * * @memberof Morebits.quickForm * @param {(object|Morebits.quickForm.element)} data - A quickform element, or the object with which * a quickform element is constructed. * @returns {Morebits.quickForm.element} - Same as what is passed to the function. */ Morebits.quickForm.prototype.append = function QuickFormAppend(data) { return this.root.append(data); }; /** * Create a new element for the the form. * * Index to Morebits.quickForm.element types: * - Global attributes: id, className, style, tooltip, extra, $data, adminonly * - `select`: A combo box (aka drop-down). * - Attributes: name, label, multiple, size, list, event, disabled * - `option`: An element for a combo box. * - Attributes: value, label, selected, disabled * - `optgroup`: A group of "option"s. * - Attributes: label, list * - `field`: A fieldset (aka group box). * - Attributes: name, label, disabled * - `checkbox`: A checkbox. Must use "list" parameter. * - Attributes: name, list, event * - Attributes (within list): name, label, value, checked, disabled, event, subgroup * - `radio`: A radio button. Must use "list" parameter. * - Attributes: name, list, event * - Attributes (within list): name, label, value, checked, disabled, event, subgroup * - `input`: A text input box. * - Attributes: name, label, value, size, placeholder, maxlength, disabled, required, readonly, event * - `number`: A number input box. * - Attributes: Everything the text `input` has, as well as: min, max, step, list * - `dyninput`: A set of text boxes with "Remove" buttons and an "Add" button. * - Attributes: name, label, min, max, sublabel, value, size, maxlength, event * - `hidden`: An invisible form field. * - Attributes: name, value * - `header`: A level 5 header. * - Attributes: label * - `div`: A generic placeholder element or label. * - Attributes: name, label * - `submit`: A submit button. Morebits.simpleWindow moves these to the footer of the dialog. * - Attributes: name, label, disabled * - `button`: A generic button. * - Attributes: name, label, disabled, event * - `textarea`: A big, multi-line text box. * - Attributes: name, label, value, cols, rows, disabled, required, readonly * - `fragment`: A DocumentFragment object. * - No attributes, and no global attributes except adminonly. * There is some difference on how types handle the `label` attribute: * - `div`, `select`, `field`, `checkbox`/`radio`, `input`, `textarea`, `header`, and `dyninput` can accept an array of items, * and the label item(s) can be `Element`s. * - `option`, `optgroup`, `_dyninput_element`, `submit`, and `button` accept only a single string. * * @memberof Morebits.quickForm * @class * @param {object} data - Object representing the quickform element. Should * specify one of the available types from the index above, as well as any * relevant and available attributes. * @example new Morebits.quickForm.element({ * name: 'target', * type: 'input', * label: 'Your target:', * tooltip: 'Enter your target. Required.', * required: true * }); */ Morebits.quickForm.element = function QuickFormElement(data) { this.data = data; this.childs = []; }; /** * @memberof Morebits.quickForm.element * @type {number} */ Morebits.quickForm.element.id = 0; /** * Appends an element to current element. * * @memberof Morebits.quickForm.element * @param {Morebits.quickForm.element} data - A quickForm element or the object required to * create the quickForm element. * @returns {Morebits.quickForm.element} The same element passed in. */ Morebits.quickForm.element.prototype.append = function QuickFormElementAppend(data) { var child; if (data instanceof Morebits.quickForm.element) { child = data; } else { child = new Morebits.quickForm.element(data); } this.childs.push(child); return child; }; /** * Renders the HTML output for the quickForm element. This should be called * without parameters: `form.render()`. * * @memberof Morebits.quickForm.element * @returns {HTMLElement} */ Morebits.quickForm.element.prototype.render = function QuickFormElementRender(internal_subgroup_id) { var currentNode = this.compute(this.data, internal_subgroup_id); for (var i = 0; i < this.childs.length; ++i) { // do not pass internal_subgroup_id to recursive calls currentNode[1].appendChild(this.childs[i].render()); } return currentNode[0]; }; /** @memberof Morebits.quickForm.element */ Morebits.quickForm.element.prototype.compute = function QuickFormElementCompute(data, in_id) { var node; var childContainer = null; var label; var id = (in_id ? in_id + '_' : '') + 'node_' + Morebits.quickForm.element.id++; if (data.adminonly && !Morebits.userIsSysop) { // hell hack alpha data.type = 'hidden'; } var i, current, subnode; switch (data.type) { case 'form': node = document.createElement('form'); node.className = 'quickform'; node.setAttribute('action', 'javascript:void(0);'); if (data.event) { node.addEventListener(data.eventType || 'submit', data.event, false); } break; case 'fragment': node = document.createDocumentFragment(); // fragments can't have any attributes, so just return it straight away return [ node, node ]; case 'select': node = document.createElement('div'); node.setAttribute('id', 'div_' + id); if (data.label) { label = node.appendChild(document.createElement('label')); label.setAttribute('for', id); label.appendChild(Morebits.createHtml(data.label)); label.style.marginRight = '3px'; } var select = node.appendChild(document.createElement('select')); if (data.event) { select.addEventListener('change', data.event, false); } if (data.multiple) { select.setAttribute('multiple', 'multiple'); } if (data.size) { select.setAttribute('size', data.size); } if (data.disabled) { select.setAttribute('disabled', 'disabled'); } select.setAttribute('name', data.name); if (data.list) { for (i = 0; i < data.list.length; ++i) { current = data.list[i]; if (current.list) { current.type = 'optgroup'; } else { current.type = 'option'; } subnode = this.compute(current); select.appendChild(subnode[0]); } } childContainer = select; break; case 'option': node = document.createElement('option'); node.values = data.value; node.setAttribute('value', data.value); if (data.selected) { node.setAttribute('selected', 'selected'); } if (data.disabled) { node.setAttribute('disabled', 'disabled'); } node.setAttribute('label', data.label); node.appendChild(document.createTextNode(data.label)); break; case 'optgroup': node = document.createElement('optgroup'); node.setAttribute('label', data.label); if (data.list) { for (i = 0; i < data.list.length; ++i) { current = data.list[i]; current.type = 'option'; // must be options here subnode = this.compute(current); node.appendChild(subnode[0]); } } break; case 'field': node = document.createElement('fieldset'); label = node.appendChild(document.createElement('legend')); label.appendChild(Morebits.createHtml(data.label)); if (data.name) { node.setAttribute('name', data.name); } if (data.disabled) { node.setAttribute('disabled', 'disabled'); } break; case 'checkbox': case 'radio': node = document.createElement('div'); if (data.list) { for (i = 0; i < data.list.length; ++i) { var cur_id = id + '_' + i; current = data.list[i]; var cur_div; if (current.type === 'header') { // inline hack cur_div = node.appendChild(document.createElement('h6')); cur_div.appendChild(document.createTextNode(current.label)); if (current.tooltip) { Morebits.quickForm.element.generateTooltip(cur_div, current); } continue; } cur_div = node.appendChild(document.createElement('div')); subnode = cur_div.appendChild(document.createElement('input')); subnode.values = current.value; subnode.setAttribute('value', current.value); subnode.setAttribute('type', data.type); subnode.setAttribute('id', cur_id); subnode.setAttribute('name', current.name || data.name); // If name is provided on the individual checkbox, add a data-single // attribute which indicates it isn't part of a list of checkboxes with // same name. Used in getInputData() if (current.name) { subnode.setAttribute('data-single', 'data-single'); } if (current.checked) { subnode.setAttribute('checked', 'checked'); } if (current.disabled) { subnode.setAttribute('disabled', 'disabled'); } label = cur_div.appendChild(document.createElement('label')); label.appendChild(Morebits.createHtml(current.label)); label.setAttribute('for', cur_id); if (current.tooltip) { Morebits.quickForm.element.generateTooltip(label, current); } // styles go on the label, doesn't make sense to style a checkbox/radio if (current.style) { label.setAttribute('style', current.style); } var event; if (current.subgroup) { var tmpgroup = current.subgroup; if (!Array.isArray(tmpgroup)) { tmpgroup = [ tmpgroup ]; } var subgroupRaw = new Morebits.quickForm.element({ type: 'div', id: id + '_' + i + '_subgroup' }); $.each(tmpgroup, function(idx, el) { var newEl = $.extend({}, el); if (!newEl.type) { newEl.type = data.type; } newEl.name = (current.name || data.name) + '.' + newEl.name; subgroupRaw.append(newEl); }); var subgroup = subgroupRaw.render(cur_id); subgroup.className = 'quickformSubgroup'; subnode.subgroup = subgroup; subnode.shown = false; event = function(e) { if (e.target.checked) { e.target.parentNode.appendChild(e.target.subgroup); if (e.target.type === 'radio') { var name = e.target.name; if (e.target.form.names[name] !== undefined) { e.target.form.names[name].parentNode.removeChild(e.target.form.names[name].subgroup); } e.target.form.names[name] = e.target; } } else { e.target.parentNode.removeChild(e.target.subgroup); } }; subnode.addEventListener('change', event, true); if (current.checked) { subnode.parentNode.appendChild(subgroup); } } else if (data.type === 'radio') { event = function(e) { if (e.target.checked) { var name = e.target.name; if (e.target.form.names[name] !== undefined) { e.target.form.names[name].parentNode.removeChild(e.target.form.names[name].subgroup); } delete e.target.form.names[name]; } }; subnode.addEventListener('change', event, true); } // add users' event last, so it can interact with the subgroup if (data.event) { subnode.addEventListener('change', data.event, false); } else if (current.event) { subnode.addEventListener('change', current.event, true); } } } if (data.shiftClickSupport && data.type === 'checkbox') { Morebits.checkboxShiftClickSupport(Morebits.quickForm.getElements(node, data.name)); } break; // input is actually a text-type, so number here inherits the same stuff case 'number': case 'input': node = document.createElement('div'); node.setAttribute('id', 'div_' + id); if (data.label) { label = node.appendChild(document.createElement('label')); label.appendChild(Morebits.createHtml(data.label)); label.setAttribute('for', data.id || id); label.style.marginRight = '3px'; } subnode = node.appendChild(document.createElement('input')); subnode.setAttribute('name', data.name); if (data.type === 'input') { subnode.setAttribute('type', 'text'); } else { subnode.setAttribute('type', 'number'); ['min', 'max', 'step', 'list'].forEach(function(att) { if (data[att]) { subnode.setAttribute(att, data[att]); } }); } ['value', 'size', 'placeholder', 'maxlength'].forEach(function(att) { if (data[att]) { subnode.setAttribute(att, data[att]); } }); ['disabled', 'required', 'readonly'].forEach(function(att) { if (data[att]) { subnode.setAttribute(att, att); } }); if (data.event) { subnode.addEventListener('keyup', data.event, false); } childContainer = subnode; break; case 'dyninput': var min = data.min || 1; var max = data.max || Infinity; node = document.createElement('div'); label = node.appendChild(document.createElement('h5')); label.appendChild(Morebits.createHtml(data.label)); var listNode = node.appendChild(document.createElement('div')); var more = this.compute({ type: 'button', label: 'daha fazla', disabled: min >= max, event: function(e) { var new_node = new Morebits.quickForm.element(e.target.sublist); e.target.area.appendChild(new_node.render()); if (++e.target.counter >= e.target.max) { e.target.setAttribute('disabled', 'disabled'); } e.stopPropagation(); } }); node.appendChild(more[0]); var moreButton = more[1]; var sublist = { type: '_dyninput_element', label: data.sublabel || data.label, name: data.name, value: data.value, size: data.size, remove: false, maxlength: data.maxlength, event: data.event }; for (i = 0; i < min; ++i) { var elem = new Morebits.quickForm.element(sublist); listNode.appendChild(elem.render()); } sublist.remove = true; sublist.morebutton = moreButton; sublist.listnode = listNode; moreButton.sublist = sublist; moreButton.area = listNode; moreButton.max = max - min; moreButton.counter = 0; break; case '_dyninput_element': // Private, similar to normal input node = document.createElement('div'); if (data.label) { label = node.appendChild(document.createElement('label')); label.appendChild(document.createTextNode(data.label)); label.setAttribute('for', id); label.style.marginRight = '3px'; } subnode = node.appendChild(document.createElement('input')); if (data.value) { subnode.setAttribute('value', data.value); } subnode.setAttribute('name', data.name); subnode.setAttribute('type', 'text'); if (data.size) { subnode.setAttribute('size', data.size); } if (data.maxlength) { subnode.setAttribute('maxlength', data.maxlength); } if (data.event) { subnode.addEventListener('keyup', data.event, false); } if (data.remove) { var remove = this.compute({ type: 'button', label: 'kaldır', event: function(e) { var list = e.target.listnode; var node = e.target.inputnode; var more = e.target.morebutton; list.removeChild(node); --more.counter; more.removeAttribute('disabled'); e.stopPropagation(); } }); node.appendChild(remove[0]); var removeButton = remove[1]; removeButton.inputnode = node; removeButton.listnode = data.listnode; removeButton.morebutton = data.morebutton; } break; case 'hidden': node = document.createElement('input'); node.setAttribute('type', 'hidden'); node.values = data.value; node.setAttribute('value', data.value); node.setAttribute('name', data.name); break; case 'header': node = document.createElement('h5'); node.appendChild(Morebits.createHtml(data.label)); break; case 'div': node = document.createElement('div'); if (data.name) { node.setAttribute('name', data.name); } if (data.label) { var result = document.createElement('span'); result.className = 'quickformDescription'; result.appendChild(Morebits.createHtml(data.label)); node.appendChild(result); } break; case 'submit': node = document.createElement('span'); childContainer = node.appendChild(document.createElement('input')); childContainer.setAttribute('type', 'submit'); if (data.label) { childContainer.setAttribute('value', data.label); } childContainer.setAttribute('name', data.name || 'submit'); if (data.disabled) { childContainer.setAttribute('disabled', 'disabled'); } break; case 'button': node = document.createElement('span'); childContainer = node.appendChild(document.createElement('input')); childContainer.setAttribute('type', 'button'); if (data.label) { childContainer.setAttribute('value', data.label); } childContainer.setAttribute('name', data.name); if (data.disabled) { childContainer.setAttribute('disabled', 'disabled'); } if (data.event) { childContainer.addEventListener('click', data.event, false); } break; case 'textarea': node = document.createElement('div'); node.setAttribute('id', 'div_' + id); if (data.label) { label = node.appendChild(document.createElement('h5')); var labelElement = document.createElement('label'); labelElement.appendChild(Morebits.createHtml(data.label)); labelElement.setAttribute('for', data.id || id); label.appendChild(labelElement); } subnode = node.appendChild(document.createElement('textarea')); subnode.setAttribute('name', data.name); if (data.cols) { subnode.setAttribute('cols', data.cols); } if (data.rows) { subnode.setAttribute('rows', data.rows); } if (data.disabled) { subnode.setAttribute('disabled', 'disabled'); } if (data.required) { subnode.setAttribute('required', 'required'); } if (data.readonly) { subnode.setAttribute('readonly', 'readonly'); } if (data.value) { subnode.value = data.value; } childContainer = subnode; break; default: throw new Error('Morebits.quickForm: unknown element type ' + data.type.toString()); } if (!childContainer) { childContainer = node; } if (data.tooltip) { Morebits.quickForm.element.generateTooltip(label || node, data); } if (data.extra) { childContainer.extra = data.extra; } if (data.$data) { $(childContainer).data(data.$data); } if (data.style) { childContainer.setAttribute('style', data.style); } if (data.className) { childContainer.className = childContainer.className ? childContainer.className + ' ' + data.className : data.className; } childContainer.setAttribute('id', data.id || id); return [ node, childContainer ]; }; /** * Create a jQuery UI-based tooltip. * * @memberof Morebits.quickForm.element * @requires jquery.ui * @param {HTMLElement} node - The HTML element beside which a tooltip is to be generated. * @param {object} data - Tooltip-related configuration data. */ Morebits.quickForm.element.generateTooltip = function QuickFormElementGenerateTooltip(node, data) { var tooltipButton = node.appendChild(document.createElement('span')); tooltipButton.className = 'morebits-tooltipButton'; tooltipButton.title = data.tooltip; // Provides the content for jQuery UI tooltipButton.appendChild(document.createTextNode(msg('tooltip-mark', '?'))); $(tooltipButton).tooltip({ position: { my: 'left top', at: 'center bottom', collision: 'flipfit' }, // Deprecated in UI 1.12, but MW stuck on 1.9.2 indefinitely; see #398 and T71386 tooltipClass: 'morebits-ui-tooltip' }); }; // Some utility methods for manipulating quickForms after their creation: // (None of these work for "dyninput" type fields at present) /** * Returns an object containing all filled form data entered by the user, with the object * keys being the form element names. Disabled fields will be ignored, but not hidden fields. * * @memberof Morebits.quickForm * @param {HTMLFormElement} form * @returns {object} With field names as keys, input data as values. */ Morebits.quickForm.getInputData = function(form) { var result = {}; for (var i = 0; i < form.elements.length; i++) { var field = form.elements[i]; if (field.disabled || !field.name || !field.type || field.type === 'submit' || field.type === 'button') { continue; } // For elements in subgroups, quickform prepends element names with // name of the parent group followed by a period, get rid of that. var fieldNameNorm = field.name.slice(field.name.indexOf('.') + 1); switch (field.type) { case 'radio': if (field.checked) { result[fieldNameNorm] = field.value; } break; case 'checkbox': if (field.dataset.single) { result[fieldNameNorm] = field.checked; // boolean } else { result[fieldNameNorm] = result[fieldNameNorm] || []; if (field.checked) { result[fieldNameNorm].push(field.value); } } break; case 'select-multiple': result[fieldNameNorm] = $(field).val(); // field.value doesn't work break; case 'text': // falls through case 'textarea': result[fieldNameNorm] = field.value.trim(); break; default: // could be select-one, date, number, email, etc if (field.value) { result[fieldNameNorm] = field.value; } break; } } return result; }; /** * Returns all form elements with a given field name or ID. * * @memberof Morebits.quickForm * @param {HTMLFormElement} form * @param {string} fieldName - The name or id of the fields. * @returns {HTMLElement[]} - Array of matching form elements. */ Morebits.quickForm.getElements = function QuickFormGetElements(form, fieldName) { var $form = $(form); fieldName = $.escapeSelector(fieldName); // sanitize input var $elements = $form.find('[name="' + fieldName + '"]'); if ($elements.length > 0) { return $elements.toArray(); } $elements = $form.find('#' + fieldName); return $elements.toArray(); }; /** * Searches the array of elements for a checkbox or radio button with a certain * `value` attribute, and returns the first such element. Returns null if not found. * * @memberof Morebits.quickForm * @param {HTMLInputElement[]} elementArray - Array of checkbox or radio elements. * @param {string} value - Value to search for. * @returns {HTMLInputElement} */ Morebits.quickForm.getCheckboxOrRadio = function QuickFormGetCheckboxOrRadio(elementArray, value) { var found = $.grep(elementArray, function(el) { return el.value === value; }); if (found.length > 0) { return found[0]; } return null; }; /** * Returns the &lt;div> containing the form element, or the form element itself * May not work as expected on checkboxes or radios. * * @memberof Morebits.quickForm * @param {HTMLElement} element * @returns {HTMLElement} */ Morebits.quickForm.getElementContainer = function QuickFormGetElementContainer(element) { // for divs, headings and fieldsets, the container is the element itself if (element instanceof HTMLFieldSetElement || element instanceof HTMLDivElement || element instanceof HTMLHeadingElement) { return element; } // for others, just return the parent node return element.parentNode; }; /** * Gets the HTML element that contains the label of the given form element * (mainly for internal use). * * @memberof Morebits.quickForm * @param {(HTMLElement|Morebits.quickForm.element)} element * @returns {HTMLElement} */ Morebits.quickForm.getElementLabelObject = function QuickFormGetElementLabelObject(element) { // for buttons, divs and headers, the label is on the element itself if (element.type === 'button' || element.type === 'submit' || element instanceof HTMLDivElement || element instanceof HTMLHeadingElement) { return element; // for fieldsets, the label is the child <legend> element } else if (element instanceof HTMLFieldSetElement) { return element.getElementsByTagName('legend')[0]; // for textareas, the label is the sibling <h5> element } else if (element instanceof HTMLTextAreaElement) { return element.parentNode.getElementsByTagName('h5')[0]; } // for others, the label is the sibling <label> element return element.parentNode.getElementsByTagName('label')[0]; }; /** * Gets the label text of the element. * * @memberof Morebits.quickForm * @param {(HTMLElement|Morebits.quickForm.element)} element * @returns {string} */ Morebits.quickForm.getElementLabel = function QuickFormGetElementLabel(element) { var labelElement = Morebits.quickForm.getElementLabelObject(element); if (!labelElement) { return null; } return labelElement.firstChild.textContent; }; /** * Sets the label of the element to the given text. * * @memberof Morebits.quickForm * @param {(HTMLElement|Morebits.quickForm.element)} element * @param {string} labelText * @returns {boolean} True if succeeded, false if the label element is unavailable. */ Morebits.quickForm.setElementLabel = function QuickFormSetElementLabel(element, labelText) { var labelElement = Morebits.quickForm.getElementLabelObject(element); if (!labelElement) { return false; } labelElement.firstChild.textContent = labelText; return true; }; /** * Stores the element's current label, and temporarily sets the label to the given text. * * @memberof Morebits.quickForm * @param {(HTMLElement|Morebits.quickForm.element)} element * @param {string} temporaryLabelText * @returns {boolean} `true` if succeeded, `false` if the label element is unavailable. */ Morebits.quickForm.overrideElementLabel = function QuickFormOverrideElementLabel(element, temporaryLabelText) { if (!element.hasAttribute('data-oldlabel')) { element.setAttribute('data-oldlabel', Morebits.quickForm.getElementLabel(element)); } return Morebits.quickForm.setElementLabel(element, temporaryLabelText); }; /** * Restores the label stored by overrideElementLabel. * * @memberof Morebits.quickForm * @param {(HTMLElement|Morebits.quickForm.element)} element * @returns {boolean} True if succeeded, false if the label element is unavailable. */ Morebits.quickForm.resetElementLabel = function QuickFormResetElementLabel(element) { if (element.hasAttribute('data-oldlabel')) { return Morebits.quickForm.setElementLabel(element, element.getAttribute('data-oldlabel')); } return null; }; /** * Shows or hides a form element plus its label and tooltip. * * @memberof Morebits.quickForm * @param {(HTMLElement|jQuery|string)} element - HTML/jQuery element, or jQuery selector string. * @param {boolean} [visibility] - Skip this to toggle visibility. */ Morebits.quickForm.setElementVisibility = function QuickFormSetElementVisibility(element, visibility) { $(element).toggle(visibility); }; /** * Shows or hides the question mark icon (which displays the tooltip) next to a form element. * * @memberof Morebits.quickForm * @param {(HTMLElement|jQuery)} element * @param {boolean} [visibility] - Skip this to toggle visibility. */ Morebits.quickForm.setElementTooltipVisibility = function QuickFormSetElementTooltipVisibility(element, visibility) { $(Morebits.quickForm.getElementContainer(element)).find('.morebits-tooltipButton').toggle(visibility); }; /** * @external HTMLFormElement */ /** * Get checked items in the form. * * @function external:HTMLFormElement.getChecked * @param {string} name - Find checked property of elements (i.e. a checkbox * or a radiobutton) with the given name, or select options that have selected * set to true (don't try to mix selects with radio/checkboxes). * @param {string} [type] - Optionally specify either radio or checkbox (for * the event that both checkboxes and radiobuttons have the same name). * @returns {string[]} - Contains the values of elements with the given name * checked property set to true. */ HTMLFormElement.prototype.getChecked = function(name, type) { var elements = this.elements[name]; if (!elements) { return []; } var return_array = []; var i; if (elements instanceof HTMLSelectElement) { var options = elements.options; for (i = 0; i < options.length; ++i) { if (options[i].selected) { if (options[i].values) { return_array.push(options[i].values); } else { return_array.push(options[i].value); } } } } else if (elements instanceof HTMLInputElement) { if (type && elements.type !== type) { return []; } else if (elements.checked) { return [ elements.value ]; } } else { for (i = 0; i < elements.length; ++i) { if (elements[i].checked) { if (type && elements[i].type !== type) { continue; } if (elements[i].values) { return_array.push(elements[i].values); } else { return_array.push(elements[i].value); } } } } return return_array; }; /** * Does the same as {@link HTMLFormElement.getChecked|getChecked}, but with unchecked elements. * * @function external:HTMLFormElement.getUnchecked * @param {string} name - Find checked property of elements (i.e. a checkbox * or a radiobutton) with the given name, or select options that have selected * set to true (don't try to mix selects with radio/checkboxes). * @param {string} [type] - Optionally specify either radio or checkbox (for * the event that both checkboxes and radiobuttons have the same name). * @returns {string[]} - Contains the values of elements with the given name * checked property set to true. */ HTMLFormElement.prototype.getUnchecked = function(name, type) { var elements = this.elements[name]; if (!elements) { return []; } var return_array = []; var i; if (elements instanceof HTMLSelectElement) { var options = elements.options; for (i = 0; i < options.length; ++i) { if (!options[i].selected) { if (options[i].values) { return_array.push(options[i].values); } else { return_array.push(options[i].value); } } } } else if (elements instanceof HTMLInputElement) { if (type && elements.type !== type) { return []; } else if (!elements.checked) { return [ elements.value ]; } } else { for (i = 0; i < elements.length; ++i) { if (!elements[i].checked) { if (type && elements[i].type !== type) { continue; } if (elements[i].values) { return_array.push(elements[i].values); } else { return_array.push(elements[i].value); } } } } return return_array; }; /** * Utilities to help process IP addresses. * * @namespace Morebits.ip * @memberof Morebits */ Morebits.ip = { /** * Converts an IPv6 address to the canonical form stored and used by MediaWiki. * JavaScript translation of the {@link https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/8eb6ac3e84ea3312d391ca96c12c49e3ad0753bb/includes/utils/IP.php#131|`IP::sanitizeIP()`} * function from the IPUtils library. Addresses are verbose, uppercase, * normalized, and expanded to 8 words. * * @param {string} address - The IPv6 address, with or without CIDR. * @returns {string} */ sanitizeIPv6: function (address) { address = address.trim(); if (address === '') { return null; } if (!mw.util.isIPv6Address(address, true)) { return address; // nothing else to do for IPv4 addresses or invalid ones } // Remove any whitespaces, convert to upper case address = address.toUpperCase(); // Expand zero abbreviations var abbrevPos = address.indexOf('::'); if (abbrevPos > -1) { // We know this is valid IPv6. Find the last index of the // address before any CIDR number (e.g. "a:b:c::/24"). var CIDRStart = address.indexOf('/'); var addressEnd = CIDRStart !== -1 ? CIDRStart - 1 : address.length - 1; // If the '::' is at the beginning... var repeat, extra, pad; if (abbrevPos === 0) { repeat = '0:'; extra = address === '::' ? '0' : ''; // for the address '::' pad = 9; // 7+2 (due to '::') // If the '::' is at the end... } else if (abbrevPos === (addressEnd - 1)) { repeat = ':0'; extra = ''; pad = 9; // 7+2 (due to '::') // If the '::' is in the middle... } else { repeat = ':0'; extra = ':'; pad = 8; // 6+2 (due to '::') } var replacement = repeat; pad -= address.split(':').length - 1; for (var i = 1; i < pad; i++) { replacement += repeat; } replacement += extra; address = address.replace('::', replacement); } // Remove leading zeros from each bloc as needed return address.replace(/(^|:)0+([0-9A-Fa-f]{1,4})/g, '$1$2'); }, /** * Determine if the given IP address is a range. Just conjoins * `mw.util.isIPAddress` with and without the `allowBlock` option. * * @param {string} ip * @returns {boolean} - True if given a valid IP address range, false otherwise. */ isRange: function (ip) { return mw.util.isIPAddress(ip, true) && !mw.util.isIPAddress(ip); }, /** * Check that an IP range is within the CIDR limits. Most likely to be useful * in conjunction with `wgRelevantUserName`. CIDR limits are hardcoded as /16 * for IPv4 and /32 for IPv6. * * @returns {boolean} - True for valid ranges within the CIDR limits, * otherwise false (ranges outside the limit, single IPs, non-IPs). */ validCIDR: function (ip) { if (Morebits.ip.isRange(ip)) { var subnet = parseInt(ip.match(/\/(\d{1,3})$/)[1], 10); if (subnet) { // Should be redundant if (mw.util.isIPv6Address(ip, true)) { if (subnet >= 32) { return true; } } else { if (subnet >= 16) { return true; } } } } return false; }, /** * Get the /64 subnet for an IPv6 address. * * @param {string} ipv6 - The IPv6 address, with or without a subnet. * @returns {boolean|string} - False if not IPv6 or bigger than a 64, * otherwise the (sanitized) /64 address. */ get64: function (ipv6) { if (!ipv6 || !mw.util.isIPv6Address(ipv6, true)) { return false; } var subnetMatch = ipv6.match(/\/(\d{1,3})$/); if (subnetMatch && parseInt(subnetMatch[1], 10) < 64) { return false; } ipv6 = Morebits.ip.sanitizeIPv6(ipv6); var ip_re = /^((?:[0-9A-F]{1,4}:){4})(?:[0-9A-F]{1,4}:){3}[0-9A-F]{1,4}(?:\/\d{1,3})?$/; return ipv6.replace(ip_re, '$1' + '0:0:0:0/64'); } }; /** * Helper functions to manipulate strings. * * @namespace Morebits.string * @memberof Morebits */ Morebits.string = { /** * @param {string} str * @returns {string} */ toUpperCaseFirstChar: function(str) { str = str.toString(); return str.substr(0, 1).toUpperCase() + str.substr(1); }, /** * @param {string} str * @returns {string} */ toLowerCaseFirstChar: function(str) { str = str.toString(); return str.substr(0, 1).toLowerCase() + str.substr(1); }, /** * Gives an array of substrings of `str` - starting with `start` and * ending with `end` - which is not in `skiplist`. Intended for use * on wikitext with templates or links. * * @param {string} str * @param {string} start * @param {string} end * @param {(string[]|string)} [skiplist] * @returns {string[]} * @throws If the `start` and `end` strings aren't of the same length. * @throws If `skiplist` isn't an array or string */ splitWeightedByKeys: function(str, start, end, skiplist) { if (start.length !== end.length) { throw new Error('start marker and end marker must be of the same length'); } var level = 0; var initial = null; var result = []; if (!Array.isArray(skiplist)) { if (skiplist === undefined) { skiplist = []; } else if (typeof skiplist === 'string') { skiplist = [ skiplist ]; } else { throw new Error('non-applicable skiplist parameter'); } } for (var i = 0; i < str.length; ++i) { for (var j = 0; j < skiplist.length; ++j) { if (str.substr(i, skiplist[j].length) === skiplist[j]) { i += skiplist[j].length - 1; continue; } } if (str.substr(i, start.length) === start) { if (initial === null) { initial = i; } ++level; i += start.length - 1; } else if (str.substr(i, end.length) === end) { --level; i += end.length - 1; } if (!level && initial !== null) { result.push(str.substring(initial, i + 1)); initial = null; } } return result; }, /** * Formats freeform "reason" (from a textarea) for deletion/other * templates that are going to be substituted, (e.g. PROD, XFD, RPP). * Handles `|` outside a nowiki tag. * Optionally, also adds a signature if not present already. * * @param {string} str * @param {boolean} [addSig] * @returns {string} */ formatReasonText: function(str, addSig) { var reason = (str || '').toString().trim(); var unbinder = new Morebits.unbinder(reason); unbinder.unbind('<no' + 'wiki>', '</no' + 'wiki>'); unbinder.content = unbinder.content.replace(/\|/g, '{{subst:!}}'); reason = unbinder.rebind(); if (addSig) { var sig = '~~~~', sigIndex = reason.lastIndexOf(sig); if (sigIndex === -1 || sigIndex !== reason.length - sig.length) { reason += ' ' + sig; } } return reason.trim(); }, /** * Formats a "reason" (from a textarea) for inclusion in a userspace * log. Replaces newlines with {{Pb}}, and adds an extra `#` before * list items for proper formatting. * * @param {string} str * @returns {string} */ formatReasonForLog: function(str) { return str // handle line breaks, which otherwise break numbering .replace(/\n+/g, '{{pb}}') // put an extra # in front before bulleted or numbered list items .replace(/^(#+)/mg, '#$1') .replace(/^(\*+)/mg, '#$1'); }, /** * Like `String.prototype.replace()`, but escapes any dollar signs in * the replacement string. Useful when the the replacement string is * arbitrary, such as a username or freeform user input, and could * contain dollar signs. * * @param {string} string - Text in which to replace. * @param {(string|RegExp)} pattern * @param {string} replacement * @returns {string} */ safeReplace: function morebitsStringSafeReplace(string, pattern, replacement) { return string.replace(pattern, replacement.replace(/\$/g, '$$$$')); }, /** * Determine if the user-provided expiration will be considered an * infinite-length by MW. * * @see {@link https://phabricator.wikimedia.org/T68646} * * @param {string} expiry * @returns {boolean} */ isInfinity: function morebitsStringIsInfinity(expiry) { return ['indefinite', 'infinity', 'infinite', 'never'].indexOf(expiry) !== -1; }, /** * Escapes a string to be used in a RegExp, replacing spaces and * underscores with `[_ ]` as they are often equivalent. * * @param {string} text - String to be escaped. * @returns {string} - The escaped text. */ escapeRegExp: function(text) { return mw.util.escapeRegExp(text).replace(/ |_/g, '[_ ]'); } }; /** * Helper functions to manipulate arrays. * * @namespace Morebits.array * @memberof Morebits */ Morebits.array = { /** * Remove duplicated items from an array. * * @param {Array} arr * @returns {Array} A copy of the array with duplicates removed. * @throws When provided a non-array. */ uniq: function(arr) { if (!Array.isArray(arr)) { throw 'A non-array object passed to Morebits.array.uniq'; } return arr.filter(function(item, idx) { return arr.indexOf(item) === idx; }); }, /** * Remove non-duplicated items from an array. * * @param {Array} arr * @returns {Array} A copy of the array with the first instance of each value * removed; subsequent instances of those values (duplicates) remain. * @throws When provided a non-array. */ dups: function(arr) { if (!Array.isArray(arr)) { throw 'A non-array object passed to Morebits.array.dups'; } return arr.filter(function(item, idx) { return arr.indexOf(item) !== idx; }); }, /** * Break up an array into smaller arrays. * * @param {Array} arr * @param {number} size - Size of each chunk (except the last, which could be different). * @returns {Array[]} An array containing the smaller, chunked arrays. * @throws When provided a non-array. */ chunk: function(arr, size) { if (!Array.isArray(arr)) { throw 'A non-array object passed to Morebits.array.chunk'; } if (typeof size !== 'number' || size <= 0) { // pretty impossible to do anything :) return [ arr ]; // we return an array consisting of this array. } var numChunks = Math.ceil(arr.length / size); var result = new Array(numChunks); for (var i = 0; i < numChunks; i++) { result[i] = arr.slice(i * size, (i + 1) * size); } return result; } }; /** * Utilities to enhance select2 menus. See twinklewarn, twinklexfd, * twinkleblock for sample usages. * * @see {@link https://select2.org/} * * @namespace Morebits.select2 * @memberof Morebits * @requires jquery.select2 */ Morebits.select2 = { matchers: { /** * Custom matcher in which if the optgroup name matches, all options in that * group are shown, like in jquery.chosen. */ optgroupFull: function(params, data) { var originalMatcher = $.fn.select2.defaults.defaults.matcher; var result = originalMatcher(params, data); if (result && params.term && data.text.toUpperCase().indexOf(params.term.toUpperCase()) !== -1) { result.children = data.children; } return result; }, /** Custom matcher that matches from the beginning of words only. */ wordBeginning: function(params, data) { var originalMatcher = $.fn.select2.defaults.defaults.matcher; var result = originalMatcher(params, data); if (!params.term || (result && new RegExp('\\b' + mw.util.escapeRegExp(params.term), 'i').test(result.text))) { return result; } return null; } }, /** Underline matched part of options. */ highlightSearchMatches: function(data) { var searchTerm = Morebits.select2SearchQuery; if (!searchTerm || data.loading) { return data.text; } var idx = data.text.toUpperCase().indexOf(searchTerm.toUpperCase()); if (idx < 0) { return data.text; } return $('<span>').append( data.text.slice(0, idx), $('<span>').css('text-decoration', 'underline').text(data.text.slice(idx, idx + searchTerm.length)), data.text.slice(idx + searchTerm.length) ); }, /** Intercept query as it is happening, for use in highlightSearchMatches. */ queryInterceptor: function(params) { Morebits.select2SearchQuery = params && params.term; }, /** * Open dropdown and begin search when the `.select2-selection` has * focus and a key is pressed. * * @see {@link https://github.com/select2/select2/issues/3279#issuecomment-442524147} */ autoStart: function(ev) { if (ev.which < 48) { return; } var target = $(ev.target).closest('.select2-container'); if (!target.length) { return; } target = target.prev(); target.select2('open'); var search = target.data('select2').dropdown.$search || target.data('select2').selection.$search; // Use DOM .focus() to work around a jQuery 3.6.0 regression (https://github.com/select2/select2/issues/5993) search[0].focus(); } }; /** * Temporarily hide a part of a string while processing the rest of it. * Used by {@link Morebits.wikitext.page#commentOutImage|Morebits.wikitext.page.commentOutImage}. * * @memberof Morebits * @class * @param {string} string - The initial text to process. * @example var u = new Morebits.unbinder('Hello world <!-- world --> world'); * u.unbind('<!--', '-->'); // text inside comment remains intact * u.content = u.content.replace(/world/g, 'earth'); * u.rebind(); // gives 'Hello earth <!-- world --> earth' */ Morebits.unbinder = function Unbinder(string) { if (typeof string !== 'string') { throw new Error('not a string'); } /** The text being processed. */ this.content = string; this.counter = 0; this.history = {}; this.prefix = '%UNIQ::' + Math.random() + '::'; this.postfix = '::UNIQ%'; }; Morebits.unbinder.prototype = { /** * Hide the region encapsulated by the `prefix` and `postfix` from * string processing. `prefix` and `postfix` will be used in a * RegExp, so items that need escaping should be use `\\`. * * @param {string} prefix * @param {string} postfix * @throws If either `prefix` or `postfix` is missing. */ unbind: function UnbinderUnbind(prefix, postfix) { if (!prefix || !postfix) { throw new Error('Both prefix and postfix must be provided'); } var re = new RegExp(prefix + '([\\s\\S]*?)' + postfix, 'g'); this.content = this.content.replace(re, Morebits.unbinder.getCallback(this)); }, /** * Restore the hidden portion of the `content` string. * * @returns {string} The processed output. */ rebind: function UnbinderRebind() { var content = this.content; content.self = this; for (var current in this.history) { if (Object.prototype.hasOwnProperty.call(this.history, current)) { content = content.replace(current, this.history[current]); } } return content; }, prefix: null, // %UNIQ::0.5955981644938324:: postfix: null, // ::UNIQ% content: null, // string counter: null, // 0++ history: null // {} }; /** @memberof Morebits.unbinder */ Morebits.unbinder.getCallback = function UnbinderGetCallback(self) { return function UnbinderCallback(match) { var current = self.prefix + self.counter + self.postfix; self.history[current] = match; ++self.counter; return current; }; }; /* **************** Morebits.date **************** */ /** * Create a date object with enhanced processing capabilities, a la * {@link https://momentjs.com/|moment.js}. MediaWiki timestamp format is also * acceptable, in addition to everything that JS Date() accepts. * * @memberof Morebits * @class */ Morebits.date = function() { var args = Array.prototype.slice.call(arguments); // Check MediaWiki formats // Must be first since firefox erroneously accepts the timestamp // format, sans timezone (See also: #921, #936, #1174, #1187), and the // 14-digit string will be interpreted differently. if (args.length === 1) { var param = args[0]; if (/^\d{14}$/.test(param)) { // YYYYMMDDHHmmss var digitMatch = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/.exec(param); if (digitMatch) { // ..... year ... month .. date ... hour .... minute ..... second this._d = new Date(Date.UTC.apply(null, [digitMatch[1], digitMatch[2] - 1, digitMatch[3], digitMatch[4], digitMatch[5], digitMatch[6]])); } } else if (typeof param === 'string') { // Wikitext signature timestamp var dateParts = Morebits.l10n.signatureTimestampFormat(param); if (dateParts) { this._d = new Date(Date.UTC.apply(null, dateParts)); } } } if (!this._d) { // Try standard date this._d = new (Function.prototype.bind.apply(Date, [Date].concat(args))); } // Still no? if (!this.isValid()) { mw.log.warn('Invalid Morebits.date initialisation:', args); } }; /** * Localized strings for date processing. * * @memberof Morebits.date * @type {object.<string, string>} * @property {string[]} months * @property {string[]} monthsShort * @property {string[]} days * @property {string[]} daysShort * @property {object.<string, string>} relativeTimes * @private */ Morebits.date.localeData = { // message names here correspond to MediaWiki message names months: [msg('january', 'Ocak'), msg('february', 'Şubat'), msg('march', 'Mart'), msg('april', 'Nisan'), msg('may_long', 'Mayıs'), msg('june', 'Haziran'), msg('july', 'Temmuz'), msg('august', 'Ağustos'), msg('september', 'Eylül'), msg('october', 'Ekim'), msg('november', 'Kasım'), msg('december', 'Aralık')], monthsShort: [msg('jan', 'Oca'), msg('feb', 'Şub'), msg('mar', 'Mar'), msg('apr', 'Nis'), msg('may', 'May'), msg('jun', 'Haz'), msg('jul', 'Tem'), msg('aug', 'Ağu'), msg('sep', 'Eyl'), msg('oct', 'Eki'), msg('nov', 'Kas'), msg('dec', 'Ara')], days: [msg('sunday', 'Pazar'), msg('monday', 'Pazartesi'), msg('tuesday', 'Salı'), msg('wednesday', 'Çarşamba'), msg('thursday', 'Perşembe'), msg('friday', 'Cuma'), msg('saturday', 'Cumartesi')], daysShort: [msg('sun', 'Paz'), msg('mon', 'Pzt'), msg('tue', 'Sal'), msg('wed', 'Çar'), msg('thu', 'Per'), msg('fri', 'Cum'), msg('sat', 'Cmt')], relativeTimes: { thisDay: msg('relative-today', '[Bugün saat] h.mm A'), prevDay: msg('relative-prevday', '[Dün saat] h.mm A'), nextDay: msg('relative-nextday', '[Yarın saat] h.mm A'), thisWeek: msg('relative-thisweek', 'dddd h.mm A'), pastWeek: msg('relative-pastweek', '[Geçen] dddd [saat] h.mm A'), other: msg('relative-other', 'DD-MM-YYYY') } }; /** * Map units with getter/setter function names, for `add` and `subtract` * methods. * * @memberof Morebits.date * @type {object.<string, string>} * @property {string} seconds * @property {string} minutes * @property {string} hours * @property {string} days * @property {string} weeks * @property {string} months * @property {string} years */ Morebits.date.unitMap = { seconds: 'Seconds', minutes: 'Minutes', hours: 'Hours', days: 'Date', weeks: 'Week', // Not a function but handled in `add` through cunning use of multiplication months: 'Month', years: 'FullYear' }; Morebits.date.prototype = { /** @returns {boolean} */ isValid: function() { return !isNaN(this.getTime()); }, /** * @param {(Date|Morebits.date)} date * @returns {boolean} */ isBefore: function(date) { return this.getTime() < date.getTime(); }, /** * @param {(Date|Morebits.date)} date * @returns {boolean} */ isAfter: function(date) { return this.getTime() > date.getTime(); }, /** @returns {string} */ getUTCMonthName: function() { return Morebits.date.localeData.months[this.getUTCMonth()]; }, /** @returns {string} */ getUTCMonthNameAbbrev: function() { return Morebits.date.localeData.monthsShort[this.getUTCMonth()]; }, /** @returns {string} */ getMonthName: function() { return Morebits.date.localeData.months[this.getMonth()]; }, /** @returns {string} */ getMonthNameAbbrev: function() { return Morebits.date.localeData.monthsShort[this.getMonth()]; }, /** @returns {string} */ getUTCDayName: function() { return Morebits.date.localeData.days[this.getUTCDay()]; }, /** @returns {string} */ getUTCDayNameAbbrev: function() { return Morebits.date.localeData.daysShort[this.getUTCDay()]; }, /** @returns {string} */ getDayName: function() { return Morebits.date.localeData.days[this.getDay()]; }, /** @returns {string} */ getDayNameAbbrev: function() { return Morebits.date.localeData.daysShort[this.getDay()]; }, /** * Add a given number of minutes, hours, days, weeks, months, or years to the date. * This is done in-place. The modified date object is also returned, allowing chaining. * * @param {number} number - Should be an integer. * @param {string} unit * @throws If invalid or unsupported unit is given. * @returns {Morebits.date} */ add: function(number, unit) { var num = parseInt(number, 10); // normalize if (isNaN(num)) { throw new Error('Geçersiz bir numara "' + number + '" sağlandı.'); } unit = unit.toLowerCase(); // normalize var unitMap = Morebits.date.unitMap; var unitNorm = unitMap[unit] || unitMap[unit + 's']; // so that both singular and plural forms work if (unitNorm) { // No built-in week functions, so rather than build out ISO's getWeek/setWeek, just multiply // Probably can't be used for Julian->Gregorian changeovers, etc. if (unitNorm === 'Week') { unitNorm = 'Date', num *= 7; } this['set' + unitNorm](this['get' + unitNorm]() + num); return this; } throw new Error('Geçersiz birim "' + unit + '": Sadece ' + Object.keys(unitMap).join(', ') + ' için izin verilir.'); }, /** * Subtracts a given number of minutes, hours, days, weeks, months, or years to the date. * This is done in-place. The modified date object is also returned, allowing chaining. * * @param {number} number - Should be an integer. * @param {string} unit * @throws If invalid or unsupported unit is given. * @returns {Morebits.date} */ subtract: function(number, unit) { return this.add(-number, unit); }, /** * Format the date into a string per the given format string. * Replacement syntax is a subset of that in moment.js: * * | Syntax | Output | * |--------|--------| * | H | Hours (24-hour) | * | HH | Hours (24-hour, padded to 2 digits) | * | h | Hours (12-hour) | * | hh | Hours (12-hour, padded to 2 digits) | * | A | AM or PM | * | m | Minutes | * | mm | Minutes (padded to 2 digits) | * | s | Seconds | * | ss | Seconds (padded to 2 digits) | * | SSS | Milliseconds fragment, 3 digits | * | d | Day number of the week (Sun=0) | * | ddd | Abbreviated day name | * | dddd | Full day name | * | D | Date | * | DD | Date (padded to 2 digits) | * | M | Month number (1-indexed) | * | MM | Month number (1-indexed, padded to 2 digits) | * | MMM | Abbreviated month name | * | MMMM | Full month name | * | Y | Year | * | YY | Final two digits of year (20 for 2020, 42 for 1942) | * | YYYY | Year (same as `Y`) | * * @param {string} formatstr - Format the date into a string, using * the replacement syntax. Use `[` and `]` to escape items. If not * provided, will return the ISO-8601-formatted string. * @param {(string|number)} [zone=system] - `system` (for browser-default time zone), * `utc`, or specify a time zone as number of minutes relative to UTC. * @returns {string} */ format: function(formatstr, zone) { if (!this.isValid()) { return 'Geçersiz tarih'; // Put the truth out, preferable to "NaNNaNNan NaN:NaN" or whatever } var udate = this; // create a new date object that will contain the date to display as system time if (zone === 'utc') { udate = new Morebits.date(this.getTime()).add(this.getTimezoneOffset(), 'minutes'); } else if (typeof zone === 'number') { // convert to utc, then add the utc offset given udate = new Morebits.date(this.getTime()).add(this.getTimezoneOffset() + zone, 'minutes'); } // default to ISOString if (!formatstr) { return udate.toISOString(); } var pad = function(num, len) { len = len || 2; // Up to length of 00 + 1 return ('00' + num).toString().slice(0 - len); }; var h24 = udate.getHours(), m = udate.getMinutes(), s = udate.getSeconds(), ms = udate.getMilliseconds(); var D = udate.getDate(), M = udate.getMonth() + 1, Y = udate.getFullYear(); var h12 = h24 % 12 || 12, amOrPm = h24 >= 12 ? msg('period-pm', 'ÖS') : msg('period-am', 'ÖÖ'); var replacementMap = { HH: pad(h24), H: h24, hh: pad(h12), h: h12, A: amOrPm, mm: pad(m), m: m, ss: pad(s), s: s, SSS: pad(ms, 3), dddd: udate.getDayName(), ddd: udate.getDayNameAbbrev(), d: udate.getDay(), DD: pad(D), D: D, MMMM: udate.getMonthName(), MMM: udate.getMonthNameAbbrev(), MM: pad(M), M: M, YYYY: Y, YY: pad(Y % 100), Y: Y }; var unbinder = new Morebits.unbinder(formatstr); // escape stuff between [...] unbinder.unbind('\\[', '\\]'); unbinder.content = unbinder.content.replace( /* Regex notes: * d(d{2,3})? matches exactly 1, 3 or 4 occurrences of 'd' ('dd' is treated as a double match of 'd') * Y{1,2}(Y{2})? matches exactly 1, 2 or 4 occurrences of 'Y' */ /H{1,2}|h{1,2}|m{1,2}|s{1,2}|SSS|d(d{2,3})?|D{1,2}|M{1,4}|Y{1,2}(Y{2})?|A/g, function(match) { return replacementMap[match]; } ); return unbinder.rebind().replace(/\[(.*?)\]/g, '$1'); }, /** * Gives a readable relative time string such as "Yesterday at 6:43 PM" or "Last Thursday at 11:45 AM". * Similar to `calendar` in moment.js, but with time zone support. * * @param {(string|number)} [zone=system] - 'system' (for browser-default time zone), * 'utc' (for UTC), or specify a time zone as number of minutes past UTC. * @returns {string} */ calendar: function(zone) { // Zero out the hours, minutes, seconds and milliseconds - keeping only the date; // find the difference. Note that setHours() returns the same thing as getTime(). var dateDiff = (new Date().setHours(0, 0, 0, 0) - new Date(this).setHours(0, 0, 0, 0)) / 8.64e7; switch (true) { case dateDiff === 0: return this.format(Morebits.date.localeData.relativeTimes.thisDay, zone); case dateDiff === 1: return this.format(Morebits.date.localeData.relativeTimes.prevDay, zone); case dateDiff > 0 && dateDiff < 7: return this.format(Morebits.date.localeData.relativeTimes.pastWeek, zone); case dateDiff === -1: return this.format(Morebits.date.localeData.relativeTimes.nextDay, zone); case dateDiff < 0 && dateDiff > -7: return this.format(Morebits.date.localeData.relativeTimes.thisWeek, zone); default: return this.format(Morebits.date.localeData.relativeTimes.other, zone); } }, /** * Get a regular expression that matches wikitext section titles, such * as `==December 2019==` or `=== Jan 2018 ===`. * * @returns {RegExp} */ monthHeaderRegex: function() { return new RegExp('^(==+)\\s*(?:' + this.getUTCMonthName() + '|' + this.getUTCMonthNameAbbrev() + ')\\s+' + this.getUTCFullYear() + '\\s*\\1', 'mg'); }, /** * Creates a wikitext section header with the month and year. * * @param {number} [level=2] - Header level. Pass 0 for just the text * with no wikitext markers (==). * @returns {string} */ monthHeader: function(level) { // Default to 2, but allow for 0 or stringy numbers level = parseInt(level, 10); level = isNaN(level) ? 2 : level; var header = Array(level + 1).join('='); // String.prototype.repeat not supported in IE 11 var text = this.getUTCMonthName() + ' ' + this.getUTCFullYear(); if (header.length) { // wikitext-formatted header return header + ' ' + text + ' ' + header; } return text; // Just the string } }; // Allow native Date.prototype methods to be used on Morebits.date objects Object.getOwnPropertyNames(Date.prototype).forEach(function(func) { // Exclude methods that collide with PageTriage's Date.js external, which clobbers native Date: [[phab:T268513]] if (['add', 'getDayName', 'getMonthName'].indexOf(func) === -1) { Morebits.date.prototype[func] = function() { return this._d[func].apply(this._d, Array.prototype.slice.call(arguments)); }; } }); /* **************** Morebits.wiki **************** */ /** * Various objects for wiki editing and API access, including * {@link Morebits.wiki.api} and {@link Morebits.wiki.page}. * * @namespace Morebits.wiki * @memberof Morebits */ Morebits.wiki = {}; /** * @deprecated in favor of Morebits.isPageRedirect as of November 2020 * @memberof Morebits.wiki * @returns {boolean} */ Morebits.wiki.isPageRedirect = function wikipediaIsPageRedirect() { console.warn('NOT: Morebits.wiki.isPageRedirect kullanımdan kaldırıldı. Bunun yerine Morebits.isPageRedirect kullanın.'); // eslint-disable-line no-console return Morebits.isPageRedirect(); }; /* **************** Morebits.wiki.actionCompleted **************** */ /** * @memberof Morebits.wiki * @type {number} */ Morebits.wiki.numberOfActionsLeft = 0; /** * @memberof Morebits.wiki * @type {number} */ Morebits.wiki.nbrOfCheckpointsLeft = 0; /** * Display message and/or redirect to page upon completion of tasks. * * Every call to Morebits.wiki.api.post() results in the dispatch of an * asynchronous callback. Each callback can in turn make an additional call to * Morebits.wiki.api.post() to continue a processing sequence. At the * conclusion of the final callback of a processing sequence, it is not * possible to simply return to the original caller because there is no call * stack leading back to the original context. Instead, * Morebits.wiki.actionCompleted.event() is called to display the result to * the user and to perform an optional page redirect. * * The determination of when to call Morebits.wiki.actionCompleted.event() is * managed through the globals Morebits.wiki.numberOfActionsLeft and * Morebits.wiki.nbrOfCheckpointsLeft. Morebits.wiki.numberOfActionsLeft is * incremented at the start of every Morebits.wiki.api call and decremented * after the completion of a callback function. If a callback function does * not create a new Morebits.wiki.api object before exiting, it is the final * step in the processing chain and Morebits.wiki.actionCompleted.event() will * then be called. * * Optionally, callers may use Morebits.wiki.addCheckpoint() to indicate that * processing is not complete upon the conclusion of the final callback * function. This is used for batch operations. The end of a batch is * signaled by calling Morebits.wiki.removeCheckpoint(). * * @memberof Morebits.wiki */ Morebits.wiki.actionCompleted = function(self) { if (--Morebits.wiki.numberOfActionsLeft <= 0 && Morebits.wiki.nbrOfCheckpointsLeft <= 0) { Morebits.wiki.actionCompleted.event(self); } }; // Change per action wanted /** @memberof Morebits.wiki */ Morebits.wiki.actionCompleted.event = function() { if (Morebits.wiki.actionCompleted.notice) { Morebits.status.actionCompleted(Morebits.wiki.actionCompleted.notice); } if (Morebits.wiki.actionCompleted.redirect) { // if it isn't a URL, make it one. TODO: This breaks on the articles 'http://', 'ftp://', and similar ones. if (!(/^\w+:\/\//).test(Morebits.wiki.actionCompleted.redirect)) { Morebits.wiki.actionCompleted.redirect = mw.util.getUrl(Morebits.wiki.actionCompleted.redirect); if (Morebits.wiki.actionCompleted.followRedirect === false) { Morebits.wiki.actionCompleted.redirect += '?redirect=no'; } } window.setTimeout(function() { window.location = Morebits.wiki.actionCompleted.redirect; }, Morebits.wiki.actionCompleted.timeOut); } }; /** @memberof Morebits.wiki */ Morebits.wiki.actionCompleted.timeOut = typeof window.wpActionCompletedTimeOut === 'undefined' ? 5000 : window.wpActionCompletedTimeOut; /** @memberof Morebits.wiki */ Morebits.wiki.actionCompleted.redirect = null; /** @memberof Morebits.wiki */ Morebits.wiki.actionCompleted.notice = null; /** @memberof Morebits.wiki */ Morebits.wiki.addCheckpoint = function() { ++Morebits.wiki.nbrOfCheckpointsLeft; }; /** @memberof Morebits.wiki */ Morebits.wiki.removeCheckpoint = function() { if (--Morebits.wiki.nbrOfCheckpointsLeft <= 0 && Morebits.wiki.numberOfActionsLeft <= 0) { Morebits.wiki.actionCompleted.event(); } }; /* **************** Morebits.wiki.api **************** */ /** * An easy way to talk to the MediaWiki API. Accepts either json or xml * (default) formats; if json is selected, will default to `formatversion=2` * unless otherwise specified. Similarly, enforces newer `errorformat`s, * defaulting to `html` if unspecified. `uselang` enforced to the wiki's * content language. * * In new code, the use of the last 3 parameters should be avoided, instead * use {@link Morebits.wiki.api#setStatusElement|setStatusElement()} to bind * the status element (if needed) and use `.then()` or `.catch()` on the * promise returned by `post()`, rather than specify the `onSuccess` or * `onFailure` callbacks. * * @memberof Morebits.wiki * @class * @param {string} currentAction - The current action (required). * @param {object} query - The query (required). * @param {Function} [onSuccess] - The function to call when request is successful. * @param {Morebits.status} [statusElement] - A Morebits.status object to use for status messages. * @param {Function} [onError] - The function to call if an error occurs. */ Morebits.wiki.api = function(currentAction, query, onSuccess, statusElement, onError) { this.currentAction = currentAction; this.query = query; this.query.assert = 'user'; // Enforce newer error formats, preferring html if (!query.errorformat || ['wikitext', 'plaintext'].indexOf(query.errorformat) === -1) { this.query.errorformat = 'html'; } // Explicitly use the wiki's content language to minimize confusion, // see #1179 for discussion this.query.uselang = 'content'; this.query.errorlang = 'uselang'; this.query.errorsuselocal = 1; this.onSuccess = onSuccess; this.onError = onError; if (statusElement) { this.setStatusElement(statusElement); } else { this.statelem = new Morebits.status(currentAction); } // JSON is used throughout Morebits/Twinkle, but xml remains the default for backwards compatibility if (!query.format) { this.query.format = 'xml'; } else if (query.format === 'json' && !query.formatversion) { this.query.formatversion = '2'; } else if (['xml', 'json'].indexOf(query.format) === -1) { this.statelem.error('Invalid API format: only xml and json are supported.'); } // Ignore tags for queries and most common unsupported actions, produces warnings if (query.action && ['query', 'review', 'stabilize', 'pagetriageaction', 'watch'].indexOf(query.action) !== -1) { delete query.tags; } else if (!query.tags && morebitsWikiChangeTag) { query.tags = morebitsWikiChangeTag; } }; Morebits.wiki.api.prototype = { currentAction: '', onSuccess: null, onError: null, parent: window, // use global context if there is no parent object query: null, response: null, responseXML: null, // use `response` instead; retained for backwards compatibility statelem: null, // this non-standard name kept for backwards compatibility statusText: null, // result received from the API, normally "success" or "error" errorCode: null, // short text error code, if any, as documented in the MediaWiki API errorText: null, // full error description, if any badtokenRetry: false, // set to true if this on a retry attempted after a badtoken error /** * Keep track of parent object for callbacks. * * @param {*} parent */ setParent: function(parent) { this.parent = parent; }, /** @param {Morebits.status} statusElement */ setStatusElement: function(statusElement) { this.statelem = statusElement; this.statelem.status(this.currentAction); }, /** * Carry out the request. * * @param {object} callerAjaxParameters - Do not specify a parameter unless you really * really want to give jQuery some extra parameters. * @returns {promise} - A jQuery promise object that is resolved or rejected with the api object. */ post: function(callerAjaxParameters) { ++Morebits.wiki.numberOfActionsLeft; var queryString = $.map(this.query, function(val, i) { if (Array.isArray(val)) { return encodeURIComponent(i) + '=' + val.map(encodeURIComponent).join('|'); } else if (val !== undefined) { return encodeURIComponent(i) + '=' + encodeURIComponent(val); } }).join('&').replace(/^(.*?)(\btoken=[^&]*)&(.*)/, '$1$3&$2'); // token should always be the last item in the query string (bug TW-B-0013) var ajaxparams = $.extend({}, { context: this, type: this.query.action === 'query' ? 'GET' : 'POST', url: mw.util.wikiScript('api'), data: queryString, dataType: this.query.format, headers: { 'Api-User-Agent': morebitsWikiApiUserAgent } }, callerAjaxParameters); return $.ajax(ajaxparams).then( function onAPIsuccess(response, statusText) { this.statusText = statusText; this.response = this.responseXML = response; // Limit to first error if (this.query.format === 'json') { this.errorCode = response.errors && response.errors[0].code; if (this.query.errorformat === 'html') { this.errorText = response.errors && response.errors[0].html; } else if (this.query.errorformat === 'wikitext' || this.query.errorformat === 'plaintext') { this.errorText = response.errors && response.errors[0].text; } } else { this.errorCode = $(response).find('errors error').eq(0).attr('code'); // Sufficient for html, wikitext, or plaintext errorformats this.errorText = $(response).find('errors error').eq(0).text(); } if (typeof this.errorCode === 'string') { // the API didn't like what we told it, e.g., bad edit token or an error creating a page return this.returnError(callerAjaxParameters); } // invoke success callback if one was supplied if (this.onSuccess) { // set the callback context to this.parent for new code and supply the API object // as the first argument to the callback (for legacy code) this.onSuccess.call(this.parent, this); } else { this.statelem.info(msg('done', 'tamamlandı')); } Morebits.wiki.actionCompleted(); return $.Deferred().resolveWith(this.parent, [this]); }, // only network and server errors reach here - complaints from the API itself are caught in success() function onAPIfailure(jqXHR, statusText, errorThrown) { this.statusText = statusText; this.errorThrown = errorThrown; // frequently undefined this.errorText = msg('api-error', statusText, jqXHR.statusText, statusText + ' "' + jqXHR.statusText + '" occurred while contacting the API.'); return this.returnError(); } ); }, returnError: function(callerAjaxParameters) { if (this.errorCode === 'badtoken' && !this.badtokenRetry) { this.statelem.warn(msg('invalid-token-retrying', 'Invalid token. Getting a new token and retrying...')); this.badtokenRetry = true; // Get a new CSRF token and retry. If the original action needs a different // type of action than CSRF, we do one pointless retry before bailing out return Morebits.wiki.api.getToken().then(function(token) { this.query.token = token; return this.post(callerAjaxParameters); }.bind(this)); } this.statelem.error(this.errorText + ' (' + this.errorCode + ')'); // invoke failure callback if one was supplied if (this.onError) { // set the callback context to this.parent for new code and supply the API object // as the first argument to the callback for legacy code this.onError.call(this.parent, this); } // don't complete the action so that the error remains displayed return $.Deferred().rejectWith(this.parent, [this]); }, getStatusElement: function() { return this.statelem; }, getErrorCode: function() { return this.errorCode; }, getErrorText: function() { return this.errorText; }, getXML: function() { // retained for backwards compatibility, use getResponse() instead return this.responseXML; }, getResponse: function() { return this.response; } }; /** Retrieves wikitext from a page. Caching enabled, duration 1 day. */ Morebits.wiki.getCachedJson = function(title) { var query = { action: 'query', prop: 'revisions', titles: title, rvslots: '*', rvprop: 'content', format: 'json', smaxage: '86400', // cache for 1 day maxage: '86400' // cache for 1 day }; return new Morebits.wiki.api('', query).post().then(function(apiobj) { apiobj.getStatusElement().unlink(); var response = apiobj.getResponse(); var wikitext = response.query.pages[0].revisions[0].slots.main.content; return JSON.parse(wikitext); }); }; var morebitsWikiApiUserAgent = 'morebits.js ([[w:WT:TW]])'; /** * Set the custom user agent header, which is used for server-side logging. * Note that doing so will set the useragent for every `Morebits.wiki.api` * process performed thereafter. * * @see {@link https://lists.wikimedia.org/pipermail/mediawiki-api-announce/2014-November/000075.html} * for original announcement. * * @memberof Morebits.wiki.api * @param {string} [ua=morebits.js ([[w:WT:TW]])] - User agent. The default * value of `morebits.js ([[w:WT:TW]])` will be appended to any provided * value. */ Morebits.wiki.api.setApiUserAgent = function(ua) { morebitsWikiApiUserAgent = (ua ? ua + ' ' : '') + 'morebits.js ([[w:WT:TW]])'; }; /** * Change/revision tag applied to Morebits actions when no other tags are specified. * Unused by default per {@link https://en.wikipedia.org/w/index.php?oldid=970618849#Adding_tags_to_Twinkle_edits_and_actions|EnWiki consensus}. * * @constant * @memberof Morebits.wiki.api * @type {string} */ var morebitsWikiChangeTag = ''; /** * Get a new CSRF token on encountering token errors. * * @memberof Morebits.wiki.api * @returns {string} MediaWiki CSRF token. */ Morebits.wiki.api.getToken = function() { var tokenApi = new Morebits.wiki.api(msg('getting-token', 'Getting token'), { action: 'query', meta: 'tokens', type: 'csrf', format: 'json' }); return tokenApi.post().then(function(apiobj) { return apiobj.response.query.tokens.csrftoken; }); }; /* **************** Morebits.wiki.page **************** */ /** * Use the MediaWiki API to load a page and optionally edit it, move it, etc. * * Callers are not permitted to directly access the properties of this class! * All property access is through the appropriate get___() or set___() method. * * Callers should set {@link Morebits.wiki.actionCompleted.notice} and {@link Morebits.wiki.actionCompleted.redirect} * before the first call to {@link Morebits.wiki.page.load()}. * * Each of the callback functions takes one parameter, which is a * reference to the Morebits.wiki.page object that registered the callback. * Callback functions may invoke any Morebits.wiki.page prototype method using this reference. * * * Call sequence for common operations (optional final user callbacks not shown): * * - Edit current contents of a page (no edit conflict): * `.load(userTextEditCallback) -> ctx.loadApi.post() -> * ctx.loadApi.post.success() -> ctx.fnLoadSuccess() -> userTextEditCallback() -> * .save() -> ctx.saveApi.post() -> ctx.loadApi.post.success() -> ctx.fnSaveSuccess()` * * - Edit current contents of a page (with edit conflict): * `.load(userTextEditCallback) -> ctx.loadApi.post() -> * ctx.loadApi.post.success() -> ctx.fnLoadSuccess() -> userTextEditCallback() -> * .save() -> ctx.saveApi.post() -> ctx.loadApi.post.success() -> * ctx.fnSaveError() -> ctx.loadApi.post() -> ctx.loadApi.post.success() -> * ctx.fnLoadSuccess() -> userTextEditCallback() -> .save() -> * ctx.saveApi.post() -> ctx.loadApi.post.success() -> ctx.fnSaveSuccess()` * * - Append to a page (similar for prepend and newSection): * `.append() -> ctx.loadApi.post() -> ctx.loadApi.post.success() -> * ctx.fnLoadSuccess() -> ctx.fnAutoSave() -> .save() -> ctx.saveApi.post() -> * ctx.loadApi.post.success() -> ctx.fnSaveSuccess()` * * Notes: * 1. All functions following Morebits.wiki.api.post() are invoked asynchronously from the jQuery AJAX library. * 2. The sequence for append/prepend/newSection could be slightly shortened, * but it would require significant duplication of code for little benefit. * * * @memberof Morebits.wiki * @class * @param {string} pageName - The name of the page, prefixed by the namespace (if any). * For the current page, use `mw.config.get('wgPageName')`. * @param {string|Morebits.status} [status] - A string describing the action about to be undertaken, * or a Morebits.status object */ Morebits.wiki.page = function(pageName, status) { if (!status) { status = msg('opening-page', pageName, '"' + pageName + '" adlı sayfa açılıyor'); } /** * Private context variables. * * This context is not visible to the outside, thus all the data here * must be accessed via getter and setter functions. * * @private */ var ctx = { // backing fields for public properties pageName: pageName, pageExists: false, editSummary: null, changeTags: null, testActions: null, // array if any valid actions callbackParameters: null, statusElement: status instanceof Morebits.status ? status : new Morebits.status(status), // - edit pageText: null, editMode: 'all', // save() replaces entire contents of the page by default appendText: null, // can't reuse pageText for this because pageText is needed to follow a redirect prependText: null, // can't reuse pageText for this because pageText is needed to follow a redirect newSectionText: null, newSectionTitle: null, createOption: null, minorEdit: false, botEdit: false, pageSection: null, maxConflictRetries: 2, maxRetries: 2, followRedirect: false, followCrossNsRedirect: true, watchlistOption: 'nochange', watchlistExpiry: null, creator: null, timestamp: null, // - revert revertOldID: null, // - move moveDestination: null, moveTalkPage: false, moveSubpages: false, moveSuppressRedirect: false, // - protect protectEdit: null, protectMove: null, protectCreate: null, protectCascade: null, // - creation lookup lookupNonRedirectCreator: false, // - stabilize (FlaggedRevs) flaggedRevs: null, // internal status pageLoaded: false, csrfToken: null, loadTime: null, lastEditTime: null, pageID: null, contentModel: null, revertCurID: null, revertUser: null, watched: false, fullyProtected: false, suppressProtectWarning: false, conflictRetries: 0, retries: 0, // callbacks onLoadSuccess: null, onLoadFailure: null, onSaveSuccess: null, onSaveFailure: null, onLookupCreationSuccess: null, onLookupCreationFailure: null, onMoveSuccess: null, onMoveFailure: null, onDeleteSuccess: null, onDeleteFailure: null, onUndeleteSuccess: null, onUndeleteFailure: null, onProtectSuccess: null, onProtectFailure: null, onStabilizeSuccess: null, onStabilizeFailure: null, // internal objects loadQuery: null, loadApi: null, saveApi: null, lookupCreationApi: null, moveApi: null, moveProcessApi: null, patrolApi: null, patrolProcessApi: null, triageApi: null, triageProcessListApi: null, triageProcessApi: null, deleteApi: null, deleteProcessApi: null, undeleteApi: null, undeleteProcessApi: null, protectApi: null, protectProcessApi: null, stabilizeApi: null, stabilizeProcessApi: null }; var emptyFunction = function() { }; /** * Loads the text for the page. * * @param {Function} onSuccess - Callback function which is called when the load has succeeded. * @param {Function} [onFailure] - Callback function which is called when the load fails. */ this.load = function(onSuccess, onFailure) { ctx.onLoadSuccess = onSuccess; ctx.onLoadFailure = onFailure || emptyFunction; // Need to be able to do something after the page loads if (!onSuccess) { ctx.statusElement.error('Internal error: no onSuccess callback provided to load()!'); ctx.onLoadFailure(this); return; } ctx.loadQuery = { action: 'query', prop: 'info|revisions', inprop: 'watched', intestactions: 'edit', // can be expanded curtimestamp: '', meta: 'tokens', type: 'csrf', titles: ctx.pageName, format: 'json' // don't need rvlimit=1 because we don't need rvstartid here and only one actual rev is returned by default }; if (ctx.editMode === 'all') { ctx.loadQuery.rvprop = 'content|timestamp'; // get the page content at the same time, if needed } else if (ctx.editMode === 'revert') { ctx.loadQuery.rvprop = 'timestamp'; ctx.loadQuery.rvlimit = 1; ctx.loadQuery.rvstartid = ctx.revertOldID; } if (ctx.followRedirect) { ctx.loadQuery.redirects = ''; // follow all redirects } if (typeof ctx.pageSection === 'number') { ctx.loadQuery.rvsection = ctx.pageSection; } if (Morebits.userIsSysop) { ctx.loadQuery.inprop += '|protection'; } ctx.loadApi = new Morebits.wiki.api(msg('retrieving-page', 'Sayfa alınıyor...'), ctx.loadQuery, fnLoadSuccess, ctx.statusElement, ctx.onLoadFailure); ctx.loadApi.setParent(this); ctx.loadApi.post(); }; /** * Saves the text for the page to Wikipedia. * Must be preceded by successfully calling `load()`. * * Warning: Calling `save()` can result in additional calls to the * previous `load()` callbacks to recover from edit conflicts! In this * case, callers must make the same edit to the new pageText and * re-invoke `save()`. This behavior can be disabled with * `setMaxConflictRetries(0)`. * * @param {Function} [onSuccess] - Callback function which is called when the save has succeeded. * @param {Function} [onFailure] - Callback function which is called when the save fails. */ this.save = function(onSuccess, onFailure) { ctx.onSaveSuccess = onSuccess; ctx.onSaveFailure = onFailure || emptyFunction; // are we getting our editing token from mw.user.tokens? var canUseMwUserToken = fnCanUseMwUserToken('edit'); if (!ctx.pageLoaded && !canUseMwUserToken) { ctx.statusElement.error('Internal error: attempt to save a page that has not been loaded!'); ctx.onSaveFailure(this); return; } if (!ctx.editSummary) { // new section mode allows (nay, encourages) using the // title as the edit summary, but the query needs // editSummary to be undefined or '', not null if (ctx.editMode === 'new' && ctx.newSectionTitle) { ctx.editSummary = ''; } else { ctx.statusElement.error('İç hata: Kaydetmeden önce değişiklik özeti belirlenmedi!'); ctx.onSaveFailure(this); return; } } // shouldn't happen if canUseMwUserToken === true if (ctx.fullyProtected && !ctx.suppressProtectWarning && !confirm( ctx.fullyProtected === 'infinity' ? msg('protected-indef-edit-warning', ctx.pageName, 'You are about to make an edit to the fully protected page "' + ctx.pageName + '" (protected indefinitely). \n\nClick OK to proceed with the edit, or Cancel to skip this edit.' ) : msg('protected-edit-warning', ctx.pageName, ctx.fullyProtected, 'You are about to make an edit to the fully protected page "' + ctx.pageName + '" (protection expiring ' + new Morebits.date(ctx.fullyProtected).calendar('utc') + ' (UTC)). \n\nClick OK to proceed with the edit, or Cancel to skip this edit.' ) ) ) { ctx.statusElement.error(msg('protected-aborted', 'Edit to fully protected page was aborted.')); ctx.onSaveFailure(this); return; } ctx.retries = 0; var query = { action: 'edit', title: ctx.pageName, summary: ctx.editSummary, token: canUseMwUserToken ? mw.user.tokens.get('csrfToken') : ctx.csrfToken, watchlist: ctx.watchlistOption, format: 'json' }; if (ctx.changeTags) { query.tags = ctx.changeTags; } if (fnApplyWatchlistExpiry()) { query.watchlistexpiry = ctx.watchlistExpiry; } if (typeof ctx.pageSection === 'number') { query.section = ctx.pageSection; } // Set minor edit attribute. If these parameters are present with any value, it is interpreted as true if (ctx.minorEdit) { query.minor = true; } else { query.notminor = true; // force Twinkle config to override user preference setting for "all edits are minor" } // Set bot edit attribute. If this parameter is present with any value, it is interpreted as true if (ctx.botEdit) { query.bot = true; } switch (ctx.editMode) { case 'append': if (ctx.appendText === null) { ctx.statusElement.error('Internal error: append text not set before save!'); ctx.onSaveFailure(this); return; } query.appendtext = ctx.appendText; // use mode to append to current page contents break; case 'prepend': if (ctx.prependText === null) { ctx.statusElement.error('Internal error: prepend text not set before save!'); ctx.onSaveFailure(this); return; } query.prependtext = ctx.prependText; // use mode to prepend to current page contents break; case 'new': if (!ctx.newSectionText) { // API doesn't allow empty new section text ctx.statusElement.error('Internal error: new section text not set before save!'); ctx.onSaveFailure(this); return; } query.section = 'new'; query.text = ctx.newSectionText; // add a new section to current page query.sectiontitle = ctx.newSectionTitle || ctx.editSummary; // done by the API, but non-'' values would get treated as text break; case 'revert': query.undo = ctx.revertCurID; query.undoafter = ctx.revertOldID; if (ctx.lastEditTime) { query.basetimestamp = ctx.lastEditTime; // check that page hasn't been edited since it was loaded } query.starttimestamp = ctx.loadTime; // check that page hasn't been deleted since it was loaded (don't recreate bad stuff) break; default: // 'all' query.text = ctx.pageText; // replace entire contents of the page if (ctx.lastEditTime) { query.basetimestamp = ctx.lastEditTime; // check that page hasn't been edited since it was loaded } query.starttimestamp = ctx.loadTime; // check that page hasn't been deleted since it was loaded (don't recreate bad stuff) break; } if (['recreate', 'createonly', 'nocreate'].indexOf(ctx.createOption) !== -1) { query[ctx.createOption] = ''; } if (canUseMwUserToken && ctx.followRedirect) { query.redirect = true; } ctx.saveApi = new Morebits.wiki.api(msg('saving-page', 'Sayfa kaydediliyor...'), query, fnSaveSuccess, ctx.statusElement, fnSaveError); ctx.saveApi.setParent(this); ctx.saveApi.post(); }; /** * Adds the text provided via `setAppendText()` to the end of the * page. Does not require calling `load()` first, unless a watchlist * expiry is used. * * @param {Function} [onSuccess] - Callback function which is called when the method has succeeded. * @param {Function} [onFailure] - Callback function which is called when the method fails. */ this.append = function(onSuccess, onFailure) { ctx.editMode = 'append'; if (fnCanUseMwUserToken('edit')) { this.save(onSuccess, onFailure); } else { ctx.onSaveSuccess = onSuccess; ctx.onSaveFailure = onFailure || emptyFunction; this.load(fnAutoSave, ctx.onSaveFailure); } }; /** * Adds the text provided via `setPrependText()` to the start of the * page. Does not require calling `load()` first, unless a watchlist * expiry is used. * * @param {Function} [onSuccess] - Callback function which is called when the method has succeeded. * @param {Function} [onFailure] - Callback function which is called when the method fails. */ this.prepend = function(onSuccess, onFailure) { ctx.editMode = 'prepend'; if (fnCanUseMwUserToken('edit')) { this.save(onSuccess, onFailure); } else { ctx.onSaveSuccess = onSuccess; ctx.onSaveFailure = onFailure || emptyFunction; this.load(fnAutoSave, ctx.onSaveFailure); } }; /** * Creates a new section with the text provided by `setNewSectionText()` * and section title from `setNewSectionTitle()`. * If `editSummary` is provided, that will be used instead of the * autogenerated "->Title (new section" edit summary. * Does not require calling `load()` first, unless a watchlist expiry * is used. * * @param {Function} [onSuccess] - Callback function which is called when the method has succeeded. * @param {Function} [onFailure] - Callback function which is called when the method fails. */ this.newSection = function(onSuccess, onFailure) { ctx.editMode = 'new'; if (fnCanUseMwUserToken('edit')) { this.save(onSuccess, onFailure); } else { ctx.onSaveSuccess = onSuccess; ctx.onSaveFailure = onFailure || emptyFunction; this.load(fnAutoSave, ctx.onSaveFailure); } }; /** @returns {string} The name of the loaded page, including the namespace */ this.getPageName = function() { return ctx.pageName; }; /** @returns {string} The text of the page after a successful load() */ this.getPageText = function() { return ctx.pageText; }; /** @param {string} pageText - Updated page text that will be saved when `save()` is called */ this.setPageText = function(pageText) { ctx.editMode = 'all'; ctx.pageText = pageText; }; /** @param {string} appendText - Text that will be appended to the page when `append()` is called */ this.setAppendText = function(appendText) { ctx.editMode = 'append'; ctx.appendText = appendText; }; /** @param {string} prependText - Text that will be prepended to the page when `prepend()` is called */ this.setPrependText = function(prependText) { ctx.editMode = 'prepend'; ctx.prependText = prependText; }; /** @param {string} newSectionText - Text that will be added in a new section on the page when `newSection()` is called */ this.setNewSectionText = function(newSectionText) { ctx.editMode = 'new'; ctx.newSectionText = newSectionText; }; /** * @param {string} newSectionTitle - Title for the new section created when `newSection()` is called * If missing, `ctx.editSummary` will be used. Issues may occur if a substituted template is used. */ this.setNewSectionTitle = function(newSectionTitle) { ctx.editMode = 'new'; ctx.newSectionTitle = newSectionTitle; }; // Edit-related setter methods: /** * Set the edit summary that will be used when `save()` is called. * Unnecessary if editMode is 'new' and newSectionTitle is provided. * * @param {string} summary */ this.setEditSummary = function(summary) { ctx.editSummary = summary; }; /** * Set any custom tag(s) to be applied to the API action. * A number of actions don't support it, most notably watch, review, * and stabilize ({@link https://phabricator.wikimedia.org/T247721|T247721}), and * pagetriageaction ({@link https://phabricator.wikimedia.org/T252980|T252980}). * * @param {string|string[]} tags - String or array of tag(s). */ this.setChangeTags = function(tags) { ctx.changeTags = tags; }; /** * @param {string} [createOption=null] - Can take the following four values: * - recreate: create the page if it does not exist, or edit it if it exists. * - createonly: create the page if it does not exist, but return an * error if it already exists. * - nocreate: don't create the page, only edit it if it already exists. * - `null`: create the page if it does not exist, unless it was deleted * in the moment between loading the page and saving the edit (default). * */ this.setCreateOption = function(createOption) { ctx.createOption = createOption; }; /** @param {boolean} minorEdit - Set true to mark the edit as a minor edit. */ this.setMinorEdit = function(minorEdit) { ctx.minorEdit = minorEdit; }; /** @param {boolean} botEdit - Set true to mark the edit as a bot edit */ this.setBotEdit = function(botEdit) { ctx.botEdit = botEdit; }; /** * @param {number} pageSection - Integer specifying the section number to load or save. * If specified as `null`, the entire page will be retrieved. */ this.setPageSection = function(pageSection) { ctx.pageSection = pageSection; }; /** * @param {number} maxConflictRetries - Number of retries for save errors involving an edit conflict or * loss of token. Default: 2. */ this.setMaxConflictRetries = function(maxConflictRetries) { ctx.maxConflictRetries = maxConflictRetries; }; /** * @param {number} maxRetries - Number of retries for save errors not involving an edit conflict or * loss of token. Default: 2. */ this.setMaxRetries = function(maxRetries) { ctx.maxRetries = maxRetries; }; /** * Set whether and how to watch the page, including setting an expiry. * * @param {boolean|string|Morebits.date|Date} [watchlistOption=false] - * Basically a mix of MW API and Twinkley options available pre-expiry: * - `true`|`'yes'`|`'watch'`: page will be added to the user's * watchlist when the action is called. Defaults to an indefinite * watch unless `watchlistExpiry` is provided. * - `false`|`'no'`|`'nochange'`: watchlist status of the page (including expiry) will not be changed. * - `'default'`|`'preferences'`: watchlist status of the page will be * set based on the user's preference settings when the action is * called. Defaults to an indefinite watch unless `watchlistExpiry` is * provided. * - `'unwatch'`: explicitly unwatch the page. * - Any other `string` or `number`, or a `Morebits.date` or `Date` * object: watch page until the specified time, deferring to * `watchlistExpiry` if provided. * @param {string|number|Morebits.date|Date} [watchlistExpiry=infinity] - * A date-like string or number, or a date object. If a string or number, * can be relative (2 weeks) or other similarly date-like (i.e. NOT "potato"): * ISO 8601: 2038-01-09T03:14:07Z * MediaWiki: 20380109031407 * UNIX: 2147483647 * SQL: 2038-01-09 03:14:07 * Can also be `infinity` or infinity-like (`infinite`, `indefinite`, and `never`). * See {@link https://phabricator.wikimedia.org/source/mediawiki-libs-Timestamp/browse/master/src/ConvertibleTimestamp.php;4e53b859a9580c55958078f46dd4f3a44d0fcaa0$57-109?as=source&blame=off} */ this.setWatchlist = function(watchlistOption, watchlistExpiry) { if (watchlistOption instanceof Morebits.date || watchlistOption instanceof Date) { watchlistOption = watchlistOption.toISOString(); } if (typeof watchlistExpiry === 'undefined') { watchlistExpiry = 'infinity'; } else if (watchlistExpiry instanceof Morebits.date || watchlistExpiry instanceof Date) { watchlistExpiry = watchlistExpiry.toISOString(); } switch (watchlistOption) { case 'nochange': case 'no': case false: case undefined: ctx.watchlistOption = 'nochange'; // The MW API allows for changing expiry with nochange (as "nochange" refers to the binary status), // but by keeping this null it will default to any existing expiry, ensure there is actually "no change." ctx.watchlistExpiry = null; break; case 'unwatch': // expiry unimportant ctx.watchlistOption = 'unwatch'; break; case 'preferences': case 'default': ctx.watchlistOption = 'preferences'; // The API allows an expiry here, but there is as of yet (T265716) // no expiry preference option, so it's a bit devoid of context. ctx.watchlistExpiry = watchlistExpiry; break; case 'watch': case 'yes': case true: ctx.watchlistOption = 'watch'; ctx.watchlistExpiry = watchlistExpiry; break; default: // Not really a "default" per se but catches "any other string" ctx.watchlistOption = 'watch'; ctx.watchlistExpiry = watchlistOption; break; } }; /** * Set a watchlist expiry. setWatchlist can mostly handle this by * itself, so this is here largely for completeness and compatibility * with the full suite of options. * * @param {string|number|Morebits.date|Date} [watchlistExpiry=infinity] - * A date-like string or number, or a date object. If a string or number, * can be relative (2 weeks) or other similarly date-like (i.e. NOT "potato"): * ISO 8601: 2038-01-09T03:14:07Z * MediaWiki: 20380109031407 * UNIX: 2147483647 * SQL: 2038-01-09 03:14:07 * Can also be `infinity` or infinity-like (`infinite`, `indefinite`, and `never`). * See {@link https://phabricator.wikimedia.org/source/mediawiki-libs-Timestamp/browse/master/src/ConvertibleTimestamp.php;4e53b859a9580c55958078f46dd4f3a44d0fcaa0$57-109?as=source&blame=off} */ this.setWatchlistExpiry = function(watchlistExpiry) { if (typeof watchlistExpiry === 'undefined') { watchlistExpiry = 'infinity'; } else if (watchlistExpiry instanceof Morebits.date || watchlistExpiry instanceof Date) { watchlistExpiry = watchlistExpiry.toISOString(); } ctx.watchlistExpiry = watchlistExpiry; }; /** * @deprecated As of December 2020, use setWatchlist. * @param {boolean} [watchlistOption=false] - * - `True`: page watchlist status will be set based on the user's * preference settings when `save()` is called. * - `False`: watchlist status of the page will not be changed. * * Watchlist notes: * 1. The MediaWiki API value of 'unwatch', which explicitly removes * the page from the user's watchlist, is not used. * 2. If both `setWatchlist()` and `setWatchlistFromPreferences()` are * called, the last call takes priority. * 3. Twinkle modules should use the appropriate preference to set the watchlist options. * 4. Most Twinkle modules use `setWatchlist()`. `setWatchlistFromPreferences()` * is only needed for the few Twinkle watchlist preferences that * accept a string value of `default`. */ this.setWatchlistFromPreferences = function(watchlistOption) { console.warn('NOTE: Morebits.wiki.page.setWatchlistFromPreferences was deprecated December 2020, please use setWatchlist'); // eslint-disable-line no-console if (watchlistOption) { ctx.watchlistOption = 'preferences'; } else { ctx.watchlistOption = 'nochange'; } }; /** * @param {boolean} [followRedirect=false] - * - `true`: a maximum of one redirect will be followed. In the event * of a redirect, a message is displayed to the user and the redirect * target can be retrieved with getPageName(). * - `false`: (default) the requested pageName will be used without regard to any redirect. * @param {boolean} [followCrossNsRedirect=true] - Not applicable if `followRedirect` is not set true. * - `true`: (default) follow redirect even if it is a cross-namespace redirect * - `false`: don't follow redirect if it is cross-namespace, edit the redirect itself. */ this.setFollowRedirect = function(followRedirect, followCrossNsRedirect) { if (ctx.pageLoaded) { ctx.statusElement.error('Internal error: cannot change redirect setting after the page has been loaded!'); return; } ctx.followRedirect = followRedirect; ctx.followCrossNsRedirect = typeof followCrossNsRedirect !== 'undefined' ? followCrossNsRedirect : ctx.followCrossNsRedirect; }; // lookup-creation setter function /** * @param {boolean} flag - If set true, the author and timestamp of * the first non-redirect version of the page is retrieved. * * Warning: * 1. If there are no revisions among the first 50 that are * non-redirects, or if there are less 50 revisions and all are * redirects, the original creation is retrieved. * 2. Revisions that the user is not privileged to access * (revdeled/suppressed) will be treated as non-redirects. * 3. Must not be used when the page has a non-wikitext contentmodel * such as Modulespace Lua or user JavaScript/CSS. */ this.setLookupNonRedirectCreator = function(flag) { ctx.lookupNonRedirectCreator = flag; }; // Move-related setter functions /** @param {string} destination */ this.setMoveDestination = function(destination) { ctx.moveDestination = destination; }; /** @param {boolean} flag */ this.setMoveTalkPage = function(flag) { ctx.moveTalkPage = !!flag; }; /** @param {boolean} flag */ this.setMoveSubpages = function(flag) { ctx.moveSubpages = !!flag; }; /** @param {boolean} flag */ this.setMoveSuppressRedirect = function(flag) { ctx.moveSuppressRedirect = !!flag; }; // Protect-related setter functions /** * @param {string} level - The right required for the specific action * e.g. autoconfirmed, sysop, templateeditor, extendedconfirmed * (enWiki-only). * @param {string} [expiry=infinity] */ this.setEditProtection = function(level, expiry) { ctx.protectEdit = { level: level, expiry: expiry || 'infinity' }; }; this.setMoveProtection = function(level, expiry) { ctx.protectMove = { level: level, expiry: expiry || 'infinity' }; }; this.setCreateProtection = function(level, expiry) { ctx.protectCreate = { level: level, expiry: expiry || 'infinity' }; }; this.setCascadingProtection = function(flag) { ctx.protectCascade = !!flag; }; this.suppressProtectWarning = function() { ctx.suppressProtectWarning = true; }; // Revert-related getters/setters: this.setOldID = function(oldID) { ctx.revertOldID = oldID; }; /** @returns {string} The current revision ID of the page */ this.getCurrentID = function() { return ctx.revertCurID; }; /** @returns {string} Last editor of the page */ this.getRevisionUser = function() { return ctx.revertUser; }; /** @returns {string} ISO 8601 timestamp at which the page was last edited. */ this.getLastEditTime = function() { return ctx.lastEditTime; }; // Miscellaneous getters/setters: /** * Define an object for use in a callback function. * * `callbackParameters` is for use by the caller only. The parameters * allow a caller to pass the proper context into its callback * function. Callers must ensure that any changes to the * callbackParameters object within a `load()` callback still permit a * proper re-entry into the `load()` callback if an edit conflict is * detected upon calling `save()`. * * @param {object} callbackParameters */ this.setCallbackParameters = function(callbackParameters) { ctx.callbackParameters = callbackParameters; }; /** * @returns {object} - The object previously set by `setCallbackParameters()`. */ this.getCallbackParameters = function() { return ctx.callbackParameters; }; /** * @param {Morebits.status} statusElement */ this.setStatusElement = function(statusElement) { ctx.statusElement = statusElement; }; /** * @returns {Morebits.status} Status element created by the constructor. */ this.getStatusElement = function() { return ctx.statusElement; }; /** * @param {string} level - The right required for edits not to require * review. Possible options: none, autoconfirmed, review (not on enWiki). * @param {string} [expiry=infinity] */ this.setFlaggedRevs = function(level, expiry) { ctx.flaggedRevs = { level: level, expiry: expiry || 'infinity' }; }; /** * @returns {boolean} True if the page existed on the wiki when it was last loaded. */ this.exists = function() { return ctx.pageExists; }; /** * @returns {string} Page ID of the page loaded. 0 if the page doesn't * exist. */ this.getPageID = function() { return ctx.pageID; }; /** * @returns {string} - Content model of the page. Possible values * include (but may not be limited to): `wikitext`, `javascript`, * `css`, `json`, `Scribunto`, `sanitized-css`, `MassMessageListContent`. * Also gettable via `mw.config.get('wgPageContentModel')`. */ this.getContentModel = function() { return ctx.contentModel; }; /** * @returns {boolean|string} - Watched status of the page. Boolean * unless it's being watched temporarily, in which case returns the * expiry string. */ this.getWatched = function () { return ctx.watched; }; /** * @returns {string} ISO 8601 timestamp at which the page was last loaded. */ this.getLoadTime = function() { return ctx.loadTime; }; /** * @returns {string} The user who created the page following `lookupCreation()`. */ this.getCreator = function() { return ctx.creator; }; /** * @returns {string} The ISOString timestamp of page creation following `lookupCreation()`. */ this.getCreationTimestamp = function() { return ctx.timestamp; }; /** @returns {boolean} whether or not you can edit the page */ this.canEdit = function() { return !!ctx.testActions && ctx.testActions.indexOf('edit') !== -1; }; /** * Retrieves the username of the user who created the page as well as * the timestamp of creation. The username can be retrieved using the * `getCreator()` function; the timestamp can be retrieved using the * `getCreationTimestamp()` function. * Prior to June 2019 known as `lookupCreator()`. * * @param {Function} onSuccess - Callback function to be called when * the username and timestamp are found within the callback. * @param {Function} [onFailure] - Callback function to be called when * the lookup fails */ this.lookupCreation = function(onSuccess, onFailure) { ctx.onLookupCreationSuccess = onSuccess; ctx.onLookupCreationFailure = onFailure || emptyFunction; if (!onSuccess) { ctx.statusElement.error('Internal error: no onSuccess callback provided to lookupCreation()!'); ctx.onLookupCreationFailure(this); return; } var query = { action: 'query', prop: 'revisions', titles: ctx.pageName, rvlimit: 1, rvprop: 'user|timestamp', rvdir: 'newer', format: 'json' }; // Only the wikitext content model can reliably handle // rvsection, others return an error when paired with the // content rvprop. Relatedly, non-wikitext models don't // understand the #REDIRECT concept, so we shouldn't attempt // the redirect resolution in fnLookupCreationSuccess if (ctx.lookupNonRedirectCreator) { query.rvsection = 0; query.rvprop += '|content'; } if (ctx.followRedirect) { query.redirects = ''; // follow all redirects } ctx.lookupCreationApi = new Morebits.wiki.api(msg('getting-creator', 'Sayfa oluşturma bilgileri alınıyor'), query, fnLookupCreationSuccess, ctx.statusElement, ctx.onLookupCreationFailure); ctx.lookupCreationApi.setParent(this); ctx.lookupCreationApi.post(); }; /** * Reverts a page to `revertOldID` set by `setOldID`. * * @param {Function} [onSuccess] - Callback function to run on success. * @param {Function} [onFailure] - Callback function to run on failure. */ this.revert = function(onSuccess, onFailure) { ctx.onSaveSuccess = onSuccess; ctx.onSaveFailure = onFailure || emptyFunction; if (!ctx.revertOldID) { ctx.statusElement.error('Internal error: revision ID to revert to was not set before revert!'); ctx.onSaveFailure(this); return; } ctx.editMode = 'revert'; this.load(fnAutoSave, ctx.onSaveFailure); }; /** * Moves a page to another title. * * @param {Function} [onSuccess] - Callback function to run on success. * @param {Function} [onFailure] - Callback function to run on failure. */ this.move = function(onSuccess, onFailure) { ctx.onMoveSuccess = onSuccess; ctx.onMoveFailure = onFailure || emptyFunction; if (!fnPreflightChecks.call(this, 'move', ctx.onMoveFailure)) { return; // abort } if (!ctx.moveDestination) { ctx.statusElement.error('Internal error: destination page name was not set before move!'); ctx.onMoveFailure(this); return; } if (fnCanUseMwUserToken('move')) { fnProcessMove.call(this, this); } else { var query = fnNeedTokenInfoQuery('move'); ctx.moveApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), query, fnProcessMove, ctx.statusElement, ctx.onMoveFailure); ctx.moveApi.setParent(this); ctx.moveApi.post(); } }; /** * Marks the page as patrolled, using `rcid` (if available) or `revid`. * * Patrolling as such doesn't need to rely on loading the page in * question; simply passing a revid to the API is sufficient, so in * those cases just using {@link Morebits.wiki.api} is probably preferable. * * No error handling since we don't actually care about the errors. */ this.patrol = function() { if (!Morebits.userIsSysop && !Morebits.userIsInGroup('patroller')) { return; } // If a link is present, don't need to check if it's patrolled if ($('.patrollink').length) { var patrolhref = $('.patrollink a').attr('href'); ctx.rcid = mw.util.getParamValue('rcid', patrolhref); fnProcessPatrol(this, this); } else { var patrolQuery = { action: 'query', prop: 'info', meta: 'tokens', type: 'patrol', // as long as we're querying, might as well get a token list: 'recentchanges', // check if the page is unpatrolled titles: ctx.pageName, rcprop: 'patrolled', rctitle: ctx.pageName, rclimit: 1, format: 'json' }; ctx.patrolApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), patrolQuery, fnProcessPatrol); ctx.patrolApi.setParent(this); ctx.patrolApi.post(); } }; /** * Marks the page as reviewed by the PageTriage extension. * * Will, by it's nature, mark as patrolled as well. Falls back to * patrolling if not in an appropriate namespace. * * Doesn't inherently rely on loading the page in question; simply * passing a `pageid` to the API is sufficient, so in those cases just * using {@link Morebits.wiki.api} is probably preferable. * * Will first check if the page is queued via * {@link Morebits.wiki.page~fnProcessTriageList|fnProcessTriageList}. * * No error handling since we don't actually care about the errors. * * @see {@link https://www.mediawiki.org/wiki/Extension:PageTriage} Referred to as "review" on-wiki. */ this.triage = function() { // Fall back to patrol if not a valid triage namespace if (mw.config.get('pageTriageNamespaces').indexOf(new mw.Title(ctx.pageName).getNamespaceId()) === -1) { this.patrol(); } else { if (!Morebits.userIsSysop && !Morebits.userIsInGroup('patroller')) { return; } // If on the page in question, don't need to query for page ID if (new mw.Title(Morebits.pageNameNorm).getPrefixedText() === new mw.Title(ctx.pageName).getPrefixedText()) { ctx.pageID = mw.config.get('wgArticleId'); fnProcessTriageList(this, this); } else { var query = fnNeedTokenInfoQuery('triage'); ctx.triageApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), query, fnProcessTriageList); ctx.triageApi.setParent(this); ctx.triageApi.post(); } } }; // |delete| is a reserved word in some flavours of JS /** * Deletes a page (for admins only). * * @param {Function} [onSuccess] - Callback function to run on success. * @param {Function} [onFailure] - Callback function to run on failure. */ this.deletePage = function(onSuccess, onFailure) { ctx.onDeleteSuccess = onSuccess; ctx.onDeleteFailure = onFailure || emptyFunction; if (!fnPreflightChecks.call(this, 'delete', ctx.onDeleteFailure)) { return; // abort } if (fnCanUseMwUserToken('delete')) { fnProcessDelete.call(this, this); } else { var query = fnNeedTokenInfoQuery('delete'); ctx.deleteApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), query, fnProcessDelete, ctx.statusElement, ctx.onDeleteFailure); ctx.deleteApi.setParent(this); ctx.deleteApi.post(); } }; /** * Undeletes a page (for admins only). * * @param {Function} [onSuccess] - Callback function to run on success. * @param {Function} [onFailure] - Callback function to run on failure. */ this.undeletePage = function(onSuccess, onFailure) { ctx.onUndeleteSuccess = onSuccess; ctx.onUndeleteFailure = onFailure || emptyFunction; if (!fnPreflightChecks.call(this, 'undelete', ctx.onUndeleteFailure)) { return; // abort } if (fnCanUseMwUserToken('undelete')) { fnProcessUndelete.call(this, this); } else { var query = fnNeedTokenInfoQuery('undelete'); ctx.undeleteApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), query, fnProcessUndelete, ctx.statusElement, ctx.onUndeleteFailure); ctx.undeleteApi.setParent(this); ctx.undeleteApi.post(); } }; /** * Protects a page (for admins only). * * @param {Function} [onSuccess] - Callback function to run on success. * @param {Function} [onFailure] - Callback function to run on failure. */ this.protect = function(onSuccess, onFailure) { ctx.onProtectSuccess = onSuccess; ctx.onProtectFailure = onFailure || emptyFunction; if (!fnPreflightChecks.call(this, 'protect', ctx.onProtectFailure)) { return; // abort } if (!ctx.protectEdit && !ctx.protectMove && !ctx.protectCreate) { ctx.statusElement.error('İç hata: protect()! değerini çağırmadan önce korumayı değiştirmeniz, taşımanız ve/veya oluşturmanız gerekir.'); ctx.onProtectFailure(this); return; } // because of the way MW API interprets protection levels // (absolute, not differential), we always need to request // protection levels from the server var query = fnNeedTokenInfoQuery('protect'); ctx.protectApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), query, fnProcessProtect, ctx.statusElement, ctx.onProtectFailure); ctx.protectApi.setParent(this); ctx.protectApi.post(); }; /** * Apply FlaggedRevs protection settings. Only works on wikis where * the extension is installed (`$wgFlaggedRevsProtection = true` * i.e. where FlaggedRevs settings appear on the "protect" tab). * * @see {@link https://www.mediawiki.org/wiki/Extension:FlaggedRevs} * Referred to as "pending changes" on-wiki. * * @param {Function} [onSuccess] * @param {Function} [onFailure] */ this.stabilize = function(onSuccess, onFailure) { ctx.onStabilizeSuccess = onSuccess; ctx.onStabilizeFailure = onFailure || emptyFunction; if (!fnPreflightChecks.call(this, 'FlaggedRevs', ctx.onStabilizeFailure)) { return; // abort } if (!ctx.flaggedRevs) { ctx.statusElement.error('Internal error: you must set flaggedRevs before calling stabilize()!'); ctx.onStabilizeFailure(this); return; } if (fnCanUseMwUserToken('stabilize')) { fnProcessStabilize.call(this, this); } else { var query = fnNeedTokenInfoQuery('stabilize'); ctx.stabilizeApi = new Morebits.wiki.api(msg('getting-token', 'retrieving token...'), query, fnProcessStabilize, ctx.statusElement, ctx.onStabilizeFailure); ctx.stabilizeApi.setParent(this); ctx.stabilizeApi.post(); } }; /* * Private member functions * These are not exposed outside */ /** * Determines whether we can save an API call by using the csrf token * sent with the page HTML, or whether we need to ask the server for * more info (e.g. protection or watchlist expiry). * * Currently used for `append`, `prepend`, `newSection`, `move`, * `stabilize`, `deletePage`, and `undeletePage`. Not used for * `protect` since it always needs to request protection status. * * @param {string} [action=edit] - The action being undertaken, e.g. * "edit" or "delete". In practice, only "edit" or "notedit" matters. * @returns {boolean} */ var fnCanUseMwUserToken = function(action) { action = typeof action !== 'undefined' ? action : 'edit'; // IE doesn't support default parameters // If a watchlist expiry is set, we must always load the page // to avoid overwriting indefinite protection. Of course, not // needed if setting indefinite watching! if (ctx.watchlistExpiry && !Morebits.string.isInfinity(ctx.watchlistExpiry)) { return false; } // API-based redirect resolution only works for action=query and // action=edit in append/prepend/new modes if (ctx.followRedirect) { if (!ctx.followCrossNsRedirect) { return false; // must load the page to check for cross namespace redirects } if (action !== 'edit' || (ctx.editMode === 'all' || ctx.editMode === 'revert')) { return false; } } // do we need to fetch the edit protection expiry? if (Morebits.userIsSysop && !ctx.suppressProtectWarning) { if (new mw.Title(Morebits.pageNameNorm).getPrefixedText() !== new mw.Title(ctx.pageName).getPrefixedText()) { return false; } // wgRestrictionEdit is null on non-existent pages, // so this neatly handles nonexistent pages var editRestriction = mw.config.get('wgRestrictionEdit'); if (!editRestriction || editRestriction.indexOf('sysop') !== -1) { return false; } } return !!mw.user.tokens.get('csrfToken'); }; /** * When functions can't use * {@link Morebits.wiki.page~fnCanUseMwUserToken|fnCanUseMwUserToken} * or require checking protection or watched status, maintain the query * in one place. Used for {@link Morebits.wiki.page#deletePage|delete}, * {@link Morebits.wiki.page#undeletePage|undelete}, * {@link* Morebits.wiki.page#protect|protect}, * {@link Morebits.wiki.page#stabilize|stabilize}, * and {@link Morebits.wiki.page#move|move} * (basically, just not {@link Morebits.wiki.page#load|load}). * * @param {string} action - The action being undertaken, e.g. "edit" or * "delete". * @returns {object} Appropriate query. */ var fnNeedTokenInfoQuery = function(action) { var query = { action: 'query', meta: 'tokens', type: 'csrf', titles: ctx.pageName, prop: 'info', inprop: 'watched', format: 'json' }; // Protection not checked for flagged-revs or non-sysop moves if (action !== 'stabilize' && (action !== 'move' || Morebits.userIsSysop)) { query.inprop += '|protection'; } if (ctx.followRedirect && action !== 'undelete') { query.redirects = ''; // follow all redirects } return query; }; // callback from loadSuccess() for append(), prepend(), and newSection() threads var fnAutoSave = function(pageobj) { pageobj.save(ctx.onSaveSuccess, ctx.onSaveFailure); }; // callback from loadApi.post() var fnLoadSuccess = function() { var response = ctx.loadApi.getResponse().query; if (!fnCheckPageName(response, ctx.onLoadFailure)) { return; // abort } var page = response.pages[0], rev; ctx.pageExists = !page.missing; if (ctx.pageExists) { rev = page.revisions[0]; ctx.lastEditTime = rev.timestamp; ctx.pageText = rev.content; ctx.pageID = page.pageid; } else { ctx.pageText = ''; // allow for concatenation, etc. ctx.pageID = 0; // nonexistent in response, matches wgArticleId } ctx.csrfToken = response.tokens.csrftoken; if (!ctx.csrfToken) { ctx.statusElement.error(msg('token-fetch-fail', 'Değişiklik tokeni alınamadı.')); ctx.onLoadFailure(this); return; } ctx.loadTime = ctx.loadApi.getResponse().curtimestamp; if (!ctx.loadTime) { ctx.statusElement.error('Mevcut zaman damgası (timestamp) alınamadı.'); ctx.onLoadFailure(this); return; } ctx.contentModel = page.contentmodel; ctx.watched = page.watchlistexpiry || page.watched; // extract protection info, to alert admins when they are about to edit a protected page // Includes cascading protection if (Morebits.userIsSysop) { var editProt = page.protection.filter(function(pr) { return pr.type === 'edit' && pr.level === 'sysop'; }).pop(); if (editProt) { ctx.fullyProtected = editProt.expiry; } else { ctx.fullyProtected = false; } } ctx.revertCurID = page.lastrevid; var testactions = page.actions; ctx.testActions = []; // was null Object.keys(testactions).forEach(function(action) { if (testactions[action]) { ctx.testActions.push(action); } }); if (ctx.editMode === 'revert') { ctx.revertCurID = rev && rev.revid; if (!ctx.revertCurID) { ctx.statusElement.error('Mevcut revizyon kimliği alınamadı.'); ctx.onLoadFailure(this); return; } ctx.revertUser = rev && rev.user; if (!ctx.revertUser) { if (rev && rev.userhidden) { // username was RevDel'd or oversighted ctx.revertUser = '<kullanıcı adı gizlendi>'; } else { ctx.statusElement.error('Düzeltmeyi yapan kullanıcı alınamadı.'); ctx.onLoadFailure(this); return; } } // set revert edit summary ctx.editSummary = ctx.revertUser + ' tarafından ' + ctx.revertOldID + ' revizyonuna [[Vikipedi:Geri döndürme|geri döndürüldü]]: ' + ctx.editSummary; } ctx.pageLoaded = true; // alert("Generate edit conflict now"); // for testing edit conflict recovery logic ctx.onLoadSuccess(this); // invoke callback }; // helper function to parse the page name returned from the API var fnCheckPageName = function(response, onFailure) { if (!onFailure) { onFailure = emptyFunction; } var page = response.pages && response.pages[0]; if (page) { // check for invalid titles if (page.invalid) { ctx.statusElement.error(msg('invalid-title', ctx.pageName, 'Sayfa başlığı geçersiz: ' + ctx.pageName)); onFailure(this); return false; // abort } // retrieve actual title of the page after normalization and redirects var resolvedName = page.title; if (response.redirects) { // check for cross-namespace redirect: var origNs = new mw.Title(ctx.pageName).namespace; var newNs = new mw.Title(resolvedName).namespace; if (origNs !== newNs && !ctx.followCrossNsRedirect) { ctx.statusElement.error(msg('cross-redirect-abort', ctx.pageName, resolvedName, ctx.pageName + ' is a cross-namespace redirect to ' + resolvedName + ', aborted')); onFailure(this); return false; } // only notify user for redirects, not normalization new Morebits.status('Not', msg('redirected', ctx.pageName, resolvedName, ctx.pageName + ' sayfasından ' + resolvedName + ' sayfasına yönlendirildi')); } ctx.pageName = resolvedName; // update to redirect target or normalized name } else { // could be a circular redirect or other problem ctx.statusElement.error(msg('redirect-resolution-fail', ctx.pageName, 'Could not resolve redirects for: ' + ctx.pageName)); onFailure(this); // force error to stay on the screen ++Morebits.wiki.numberOfActionsLeft; return false; // abort } return true; // all OK }; /** * Determine whether we should provide a watchlist expiry. Will not * do so if the page is currently permanently watched, or the current * expiry is *after* the new, provided expiry. Only handles strings * recognized by {@link Morebits.date} or relative timeframes with * unit it can process. Relies on the fact that fnCanUseMwUserToken * requires page loading if a watchlistexpiry is provided, so we are * ensured of knowing the watch status by the use of this. * * @returns {boolean} */ var fnApplyWatchlistExpiry = function() { if (ctx.watchlistExpiry) { if (!ctx.watched || Morebits.string.isInfinity(ctx.watchlistExpiry)) { return true; } else if (typeof ctx.watched === 'string') { var newExpiry; // Attempt to determine if the new expiry is a // relative (e.g. `1 month`) or absolute datetime var rel = ctx.watchlistExpiry.split(' '); try { newExpiry = new Morebits.date().add(rel[0], rel[1]); } catch (e) { newExpiry = new Morebits.date(ctx.watchlistExpiry); } // If the date is valid, only use it if it extends the current expiry if (newExpiry.isValid()) { if (newExpiry.isAfter(new Morebits.date(ctx.watched))) { return true; } } else { // If it's still not valid, hope it's a valid MW expiry format that // Morebits.date doesn't recognize, so just default to using it. // This will also include minor typos. return true; } } } return false; }; // callback from saveApi.post() var fnSaveSuccess = function() { ctx.editMode = 'all'; // cancel append/prepend/newSection/revert modes var response = ctx.saveApi.getResponse(); // see if the API thinks we were successful if (response.edit.result === 'Success') { // real success // default on success action - display link for edited page var link = document.createElement('a'); link.setAttribute('href', mw.util.getUrl(ctx.pageName)); link.appendChild(document.createTextNode(ctx.pageName)); ctx.statusElement.info(['tamamlandı (', link, ')']); if (ctx.onSaveSuccess) { ctx.onSaveSuccess(this); // invoke callback } return; } // errors here are only generated by extensions which hook APIEditBeforeSave within MediaWiki, // which as of 1.34.0-wmf.23 (Sept 2019) should only encompass captcha messages if (response.edit.captcha) { ctx.statusElement.error('Viki sunucusu sizden bir CAPTCHA doldurmanızı istediği için sayfa kaydedilemedi.'); } else { ctx.statusElement.error(msg('api-error-unknown', 'Sayfa kaydedilirken API\'den bilinmeyen bir hata alındı')); } // force error to stay on the screen ++Morebits.wiki.numberOfActionsLeft; ctx.onSaveFailure(this); }; // callback from saveApi.post() var fnSaveError = function() { var errorCode = ctx.saveApi.getErrorCode(); // check for edit conflict if (errorCode === 'editconflict' && ctx.conflictRetries++ < ctx.maxConflictRetries) { // edit conflicts can occur when the page needs to be purged from the server cache var purgeQuery = { action: 'purge', titles: ctx.pageName // redirects are already resolved }; var purgeApi = new Morebits.wiki.api(msg('editconflict-purging', 'Değişiklik çakışması tespit edildi, sunucu önbelleği temizleniyor'), purgeQuery, function() { --Morebits.wiki.numberOfActionsLeft; // allow for normal completion if retry succeeds ctx.statusElement.info(msg('editconflict-retrying', 'Değişiklik çakışması tespit edildi, değişiklik yeniden uygulanıyor')); if (fnCanUseMwUserToken('edit')) { ctx.saveApi.post(); // necessarily append, prepend, or newSection, so this should work as desired } else { ctx.loadApi.post(); // reload the page and reapply the edit } }, ctx.statusElement); purgeApi.post(); // check for network or server error } else if ((errorCode === null || errorCode === undefined) && ctx.retries++ < ctx.maxRetries) { // the error might be transient, so try again ctx.statusElement.info(msg('save-failed-retrying', 2, 'Kaydetme başarısız, 2 saniye içinde yeniden deneniyor')); --Morebits.wiki.numberOfActionsLeft; // allow for normal completion if retry succeeds // wait for sometime for client to regain connectivity sleep(2000).then(function() { ctx.saveApi.post(); // give it another go! }); // hard error, give up } else { switch (errorCode) { case 'protectedpage': // non-admin attempting to edit a protected page - this gives a friendlier message than the default ctx.statusElement.error('Sayfa kaydedilemedi: Sayfa koruma altında'); break; case 'abusefilter-disallowed': ctx.statusElement.error('Değişiklik süzgeci değişikliğe izin vermedi: "' + ctx.saveApi.getResponse().error.abusefilter.description + '".'); break; case 'abusefilter-warning': ctx.statusElement.error([ 'Değişiklik süzgeci bir uyarı verdi: "', ctx.saveApi.getResponse().error.abusefilter.description, '". Değişikliğe devam etmek istiyorsanız lütfen bir kez daha gerçekleştirin. Uyarı ikinci kez görünmeyecektir.' ]); // We should provide the user with a way to automatically retry the action if they so choose - // I can't see how to do this without creating a UI dependency on Morebits.wiki.page though -- TTO break; case 'spamblacklist': // If multiple items are blacklisted, we only return the first var spam = ctx.saveApi.getResponse().error.spamblacklist.matches[0]; ctx.statusElement.error('Sayfa kaydedilemedi çünkü ' + spam + ' biçimindeki URL reklam kara listesinde bulunuyor'); break; default: ctx.statusElement.error('Değişiklik kaydedilemedi: ' + ctx.saveApi.getErrorText()); } ctx.editMode = 'all'; // cancel append/prepend/newSection/revert modes if (ctx.onSaveFailure) { ctx.onSaveFailure(this); // invoke callback } } }; var isTextRedirect = function(text) { if (!text) { // no text - content empty or inaccessible (revdelled or suppressed) return false; } return Morebits.l10n.redirectTagAliases.some(function(tag) { return new RegExp('^\\s*' + tag + '\\W', 'i').test(text); }); }; var fnLookupCreationSuccess = function() { var response = ctx.lookupCreationApi.getResponse().query; if (!fnCheckPageName(response, ctx.onLookupCreationFailure)) { return; // abort } var rev = response.pages[0].revisions && response.pages[0].revisions[0]; if (!rev) { ctx.statusElement.error(ctx.pageName + ' sayfasının herhangi bir revizyonu bulunamadı'); ctx.onLookupCreationFailure(this); return; } if (!ctx.lookupNonRedirectCreator || !isTextRedirect(rev.content)) { ctx.creator = rev.user; if (!ctx.creator) { ctx.statusElement.error('Sayfayı oluşturan kullanıcının adı bulunamadı'); ctx.onLookupCreationFailure(this); return; } ctx.timestamp = rev.timestamp; if (!ctx.timestamp) { ctx.statusElement.error('Sayfa oluşturma zaman damgası bulunamadı'); ctx.onLookupCreationFailure(this); return; } ctx.statusElement.info('retrieved page creation information'); ctx.onLookupCreationSuccess(this); } else { ctx.lookupCreationApi.query.rvlimit = 50; // modify previous query to fetch more revisions ctx.lookupCreationApi.query.titles = ctx.pageName; // update pageName if redirect resolution took place in earlier query ctx.lookupCreationApi = new Morebits.wiki.api('Retrieving page creation information', ctx.lookupCreationApi.query, fnLookupNonRedirectCreator, ctx.statusElement, ctx.onLookupCreationFailure); ctx.lookupCreationApi.setParent(this); ctx.lookupCreationApi.post(); } }; var fnLookupNonRedirectCreator = function() { var response = ctx.lookupCreationApi.getResponse().query; var revs = response.pages[0].revisions; for (var i = 0; i < revs.length; i++) { if (!isTextRedirect(revs[i].content)) { ctx.creator = revs[i].user; ctx.timestamp = revs[i].timestamp; break; } } if (!ctx.creator) { // fallback to give first revision author if no non-redirect version in the first 50 ctx.creator = revs[0].user; ctx.timestamp = revs[0].timestamp; if (!ctx.creator) { ctx.statusElement.error('Could not find name of page creator'); ctx.onLookupCreationFailure(this); return; } } if (!ctx.timestamp) { ctx.statusElement.error('Could not find timestamp of page creation'); ctx.onLookupCreationFailure(this); return; } ctx.statusElement.info('retrieved page creation information'); ctx.onLookupCreationSuccess(this); }; /** * Common checks for action methods. Used for move, undelete, delete, * protect, stabilize. * * @param {string} action - The action being checked. * @param {string} onFailure - Failure callback. * @returns {boolean} */ var fnPreflightChecks = function(action, onFailure) { // if a non-admin tries to do this, don't bother if (!Morebits.userIsSysop && action !== 'move') { ctx.statusElement.error('Sayfada ' + action + 'işlemi gerçekleştirilemedi: Bunu yalnızca hizmetliler yapabilir'); onFailure(this); return false; } if (!ctx.editSummary) { ctx.statusElement.error('İç hata: ' + action + ' gerekçesi belirtilmedi (setEditSummary işlevini kullanın)!'); onFailure(this); return false; } return true; // all OK }; /** * Common checks for fnProcess functions (`fnProcessDelete`, `fnProcessMove`, etc. * Used for move, undelete, delete, protect, stabilize. * * @param {string} action - The action being checked. * @param {string} onFailure - Failure callback. * @param {string} response - The response document from the API call. * @returns {boolean} */ var fnProcessChecks = function(action, onFailure, response) { var missing = response.pages[0].missing; // No undelete as an existing page could have deleted revisions var actionMissing = missing && ['delete', 'stabilize', 'move'].indexOf(action) !== -1; var protectMissing = action === 'protect' && missing && (ctx.protectEdit || ctx.protectMove); var saltMissing = action === 'protect' && !missing && ctx.protectCreate; if (actionMissing || protectMissing || saltMissing) { ctx.statusElement.error('Sayfada ' + action + ' işlemi gerçekleştirilemedi, çünkü ' + (missing ? 'artık mevcut değil' : 'zaten mevcut') + ''); onFailure(this); return false; } // Delete, undelete, move // extract protection info var editprot; if (action === 'undelete') { editprot = response.pages[0].protection.filter(function(pr) { return pr.type === 'create' && pr.level === 'sysop'; }).pop(); } else if (action === 'delete' || action === 'move') { editprot = response.pages[0].protection.filter(function(pr) { return pr.type === 'edit' && pr.level === 'sysop'; }).pop(); } if (editprot && !ctx.suppressProtectWarning && !confirm('Tam koruma altındaki bir sayfada ' + action + ' işlemi gerçekleştirmek üzeresiniz "' + ctx.pageName + (editprot.expiry === 'infinity' ? '" (süresiz koruma)' : '" (bitiş: ' + new Morebits.date(editprot.expiry).calendar('utc') + ' (UTC))') + '. \n\n' + action + ' işlemine devam etmek için Tamam, iptal etmek için İptal seçeneğine tıklayın.')) { ctx.statusElement.error('Tam koruma altındaki sayfadaki ' + action + ' işlemi iptal edildi.'); onFailure(this); return false; } if (!response.tokens.csrftoken) { ctx.statusElement.error('Token alınamadı.'); onFailure(this); return false; } return true; // all OK }; var fnProcessMove = function() { var pageTitle, token; if (fnCanUseMwUserToken('move')) { token = mw.user.tokens.get('csrfToken'); pageTitle = ctx.pageName; } else { var response = ctx.moveApi.getResponse().query; if (!fnProcessChecks('move', ctx.onMoveFailure, response)) { return; // abort } token = response.tokens.csrftoken; var page = response.pages[0]; pageTitle = page.title; ctx.watched = page.watchlistexpiry || page.watched; } var query = { action: 'move', from: pageTitle, to: ctx.moveDestination, token: token, reason: ctx.editSummary, watchlist: ctx.watchlistOption, format: 'json' }; if (ctx.changeTags) { query.tags = ctx.changeTags; } if (fnApplyWatchlistExpiry()) { query.watchlistexpiry = ctx.watchlistExpiry; } if (ctx.moveTalkPage) { query.movetalk = 'true'; } if (ctx.moveSubpages) { query.movesubpages = 'true'; } if (ctx.moveSuppressRedirect) { query.noredirect = 'true'; } ctx.moveProcessApi = new Morebits.wiki.api(msg('moving-page', 'sayfa taşınıyor...'), query, ctx.onMoveSuccess, ctx.statusElement, ctx.onMoveFailure); ctx.moveProcessApi.setParent(this); ctx.moveProcessApi.post(); }; var fnProcessPatrol = function() { var query = { action: 'patrol', format: 'json' }; // Didn't need to load the page if (ctx.rcid) { query.rcid = ctx.rcid; query.token = mw.user.tokens.get('patrolToken'); } else { var response = ctx.patrolApi.getResponse().query; // Don't patrol if not unpatrolled if (!response.recentchanges[0].unpatrolled) { return; } var lastrevid = response.pages[0].lastrevid; if (!lastrevid) { return; } query.revid = lastrevid; var token = response.tokens.csrftoken; if (!token) { return; } query.token = token; } if (ctx.changeTags) { query.tags = ctx.changeTags; } var patrolStat = new Morebits.status('Sayfa kontrol edildi olarak işaretleniyor'); ctx.patrolProcessApi = new Morebits.wiki.api('kontrol edildi olarak işaretleniyor...', query, null, patrolStat); ctx.patrolProcessApi.setParent(this); ctx.patrolProcessApi.post(); }; // Ensure that the page is curatable var fnProcessTriageList = function() { if (ctx.pageID) { ctx.csrfToken = mw.user.tokens.get('csrfToken'); } else { var response = ctx.triageApi.getResponse().query; ctx.pageID = response.pages[0].pageid; if (!ctx.pageID) { return; } ctx.csrfToken = response.tokens.csrftoken; if (!ctx.csrfToken) { return; } } var query = { action: 'pagetriagelist', page_id: ctx.pageID, format: 'json' }; ctx.triageProcessListApi = new Morebits.wiki.api('checking curation status...', query, fnProcessTriage); ctx.triageProcessListApi.setParent(this); ctx.triageProcessListApi.post(); }; // callback from triageProcessListApi.post() var fnProcessTriage = function() { var responseList = ctx.triageProcessListApi.getResponse().pagetriagelist; // Exit if not in the queue if (!responseList || responseList.result !== 'success') { return; } var page = responseList.pages && responseList.pages[0]; // Do nothing if page already triaged/patrolled if (!page || !parseInt(page.patrol_status, 10)) { var query = { action: 'pagetriageaction', pageid: ctx.pageID, reviewed: 1, // tags: ctx.changeTags, // pagetriage tag support: [[phab:T252980]] // Could use an adder to modify/create note: // summaryAd, but that seems overwrought token: ctx.csrfToken, format: 'json' }; var triageStat = new Morebits.status('Marking page as curated'); ctx.triageProcessApi = new Morebits.wiki.api('curating page...', query, null, triageStat); ctx.triageProcessApi.setParent(this); ctx.triageProcessApi.post(); } }; var fnProcessDelete = function() { var pageTitle, token; if (fnCanUseMwUserToken('delete')) { token = mw.user.tokens.get('csrfToken'); pageTitle = ctx.pageName; } else { var response = ctx.deleteApi.getResponse().query; if (!fnProcessChecks('delete', ctx.onDeleteFailure, response)) { return; // abort } token = response.tokens.csrftoken; var page = response.pages[0]; pageTitle = page.title; ctx.watched = page.watchlistexpiry || page.watched; } var query = { action: 'delete', title: pageTitle, token: token, reason: ctx.editSummary, watchlist: ctx.watchlistOption, format: 'json' }; if (ctx.changeTags) { query.tags = ctx.changeTags; } if (fnApplyWatchlistExpiry()) { query.watchlistexpiry = ctx.watchlistExpiry; } ctx.deleteProcessApi = new Morebits.wiki.api('sayfa siliniyor...', query, ctx.onDeleteSuccess, ctx.statusElement, fnProcessDeleteError); ctx.deleteProcessApi.setParent(this); ctx.deleteProcessApi.post(); }; // callback from deleteProcessApi.post() var fnProcessDeleteError = function() { var errorCode = ctx.deleteProcessApi.getErrorCode(); // check for "Database query error" if (errorCode === 'internal_api_error_DBQueryError' && ctx.retries++ < ctx.maxRetries) { ctx.statusElement.info('Database query error, retrying'); --Morebits.wiki.numberOfActionsLeft; // allow for normal completion if retry succeeds ctx.deleteProcessApi.post(); // give it another go! } else if (errorCode === 'missingtitle') { ctx.statusElement.error('Artık mevcut olmadığından dolayı sayfa silinemez'); if (ctx.onDeleteFailure) { ctx.onDeleteFailure.call(this, ctx.deleteProcessApi); // invoke callback } // hard error, give up } else { ctx.statusElement.error('Sayfa silinemedi: ' + ctx.deleteProcessApi.getErrorText()); if (ctx.onDeleteFailure) { ctx.onDeleteFailure.call(this, ctx.deleteProcessApi); // invoke callback } } }; var fnProcessUndelete = function() { var pageTitle, token; if (fnCanUseMwUserToken('undelete')) { token = mw.user.tokens.get('csrfToken'); pageTitle = ctx.pageName; } else { var response = ctx.undeleteApi.getResponse().query; if (!fnProcessChecks('undelete', ctx.onUndeleteFailure, response)) { return; // abort } token = response.tokens.csrftoken; var page = response.pages[0]; pageTitle = page.title; ctx.watched = page.watchlistexpiry || page.watched; } var query = { action: 'undelete', title: pageTitle, token: token, reason: ctx.editSummary, watchlist: ctx.watchlistOption, format: 'json' }; if (ctx.changeTags) { query.tags = ctx.changeTags; } if (ctx.watchlistExpiry && ctx.watched !== true) { query.watchlistexpiry = ctx.watchlistExpiry; } ctx.undeleteProcessApi = new Morebits.wiki.api('sayfa geri getiriliyor...', query, ctx.onUndeleteSuccess, ctx.statusElement, fnProcessUndeleteError); ctx.undeleteProcessApi.setParent(this); ctx.undeleteProcessApi.post(); }; // callback from undeleteProcessApi.post() var fnProcessUndeleteError = function() { var errorCode = ctx.undeleteProcessApi.getErrorCode(); // check for "Database query error" if (errorCode === 'internal_api_error_DBQueryError') { if (ctx.retries++ < ctx.maxRetries) { ctx.statusElement.info('Database query error, retrying'); --Morebits.wiki.numberOfActionsLeft; // allow for normal completion if retry succeeds ctx.undeleteProcessApi.post(); // give it another go! } else { ctx.statusElement.error('Yinelenen veritabanı sorgu hatası, lütfen tekrar deneyin'); if (ctx.onUndeleteFailure) { ctx.onUndeleteFailure.call(this, ctx.undeleteProcessApi); // invoke callback } } } else if (errorCode === 'cantundelete') { ctx.statusElement.error('Sayfanın geri getirilemiyor, çünkü geri getirilecek revizyon mevcut değil ya da sayfa zaten geri getirilmiş'); if (ctx.onUndeleteFailure) { ctx.onUndeleteFailure.call(this, ctx.undeleteProcessApi); // invoke callback } // hard error, give up } else { ctx.statusElement.error('Sayfa geri getirilemedi: ' + ctx.undeleteProcessApi.getErrorText()); if (ctx.onUndeleteFailure) { ctx.onUndeleteFailure.call(this, ctx.undeleteProcessApi); // invoke callback } } }; var fnProcessProtect = function() { var response = ctx.protectApi.getResponse().query; if (!fnProcessChecks('protect', ctx.onProtectFailure, response)) { return; // abort } var token = response.tokens.csrftoken; var page = response.pages[0]; var pageTitle = page.title; ctx.watched = page.watchlistexpiry || page.watched; // Fetch existing protection levels var prs = response.pages[0].protection; var editprot, moveprot, createprot; prs.forEach(function(pr) { // Filter out protection from cascading if (pr.type === 'edit' && !pr.source) { editprot = pr; } else if (pr.type === 'move') { moveprot = pr; } else if (pr.type === 'create') { createprot = pr; } }); // Fall back to current levels if not explicitly set if (!ctx.protectEdit && editprot) { ctx.protectEdit = { level: editprot.level, expiry: editprot.expiry }; } if (!ctx.protectMove && moveprot) { ctx.protectMove = { level: moveprot.level, expiry: moveprot.expiry }; } if (!ctx.protectCreate && createprot) { ctx.protectCreate = { level: createprot.level, expiry: createprot.expiry }; } // Default to pre-existing cascading protection if unchanged (similar to above) if (ctx.protectCascade === null) { ctx.protectCascade = !!prs.filter(function(pr) { return pr.cascade; }).length; } // Warn if cascading protection being applied with an invalid protection level, // which for edit protection will cause cascading to be silently stripped if (ctx.protectCascade) { // On move protection, this is technically stricter than the MW API, // but seems reasonable to avoid dumb values and misleading log entries (T265626) if (((!ctx.protectEdit || ctx.protectEdit.level !== 'sysop') || (!ctx.protectMove || ctx.protectMove.level !== 'sysop')) && !confirm('You have cascading protection enabled on "' + ctx.pageName + '" but have not selected uniform sysop-level protection.\n\n' + 'Click OK to adjust and proceed with sysop-level cascading protection, or Cancel to skip this action.')) { ctx.statusElement.error('Cascading protection was aborted.'); ctx.onProtectFailure(this); return; } ctx.protectEdit.level = 'sysop'; ctx.protectMove.level = 'sysop'; } // Build protection levels and expirys (expiries?) for query var protections = [], expirys = []; if (ctx.protectEdit) { protections.push('edit=' + ctx.protectEdit.level); expirys.push(ctx.protectEdit.expiry); } if (ctx.protectMove) { protections.push('move=' + ctx.protectMove.level); expirys.push(ctx.protectMove.expiry); } if (ctx.protectCreate) { protections.push('create=' + ctx.protectCreate.level); expirys.push(ctx.protectCreate.expiry); } var query = { action: 'protect', title: pageTitle, token: token, protections: protections.join('|'), expiry: expirys.join('|'), reason: ctx.editSummary, watchlist: ctx.watchlistOption, format: 'json' }; // Only shows up in logs, not page history [[phab:T259983]] if (ctx.changeTags) { query.tags = ctx.changeTags; } if (fnApplyWatchlistExpiry()) { query.watchlistexpiry = ctx.watchlistExpiry; } if (ctx.protectCascade) { query.cascade = 'true'; } ctx.protectProcessApi = new Morebits.wiki.api('sayfa korumaya alınıyor...', query, ctx.onProtectSuccess, ctx.statusElement, ctx.onProtectFailure); ctx.protectProcessApi.setParent(this); ctx.protectProcessApi.post(); }; var fnProcessStabilize = function() { var pageTitle, token; if (fnCanUseMwUserToken('stabilize')) { token = mw.user.tokens.get('csrfToken'); pageTitle = ctx.pageName; } else { var response = ctx.stabilizeApi.getResponse().query; // 'stabilize' as a verb not necessarily well understood if (!fnProcessChecks('stabilize', ctx.onStabilizeFailure, response)) { return; // abort } token = response.tokens.csrftoken; var page = response.pages[0]; pageTitle = page.title; // Doesn't support watchlist expiry [[phab:T263336]] // ctx.watched = page.watchlistexpiry || page.watched; } var query = { action: 'stabilize', title: pageTitle, token: token, protectlevel: ctx.flaggedRevs.level, expiry: ctx.flaggedRevs.expiry, // tags: ctx.changeTags, // flaggedrevs tag support: [[phab:T247721]] reason: ctx.editSummary, watchlist: ctx.watchlistOption, format: 'json' }; /* Doesn't support watchlist expiry [[phab:T263336]] if (fnApplyWatchlistExpiry()) { query.watchlistexpiry = ctx.watchlistExpiry; } */ ctx.stabilizeProcessApi = new Morebits.wiki.api('stabilizasyon ayarları değiştiriliyor...', query, ctx.onStabilizeSuccess, ctx.statusElement, ctx.onStabilizeFailure); ctx.stabilizeProcessApi.setParent(this); ctx.stabilizeProcessApi.post(); }; var sleep = function(milliseconds) { var deferred = $.Deferred(); setTimeout(deferred.resolve, milliseconds); return deferred; }; }; // end Morebits.wiki.page /* Morebits.wiki.page TODO: (XXX) * - Should we retry loads also? * - Need to reset current action before the save? * - Deal with action.completed stuff * - Need to reset all parameters once done (e.g. edit summary, move destination, etc.) */ /* **************** Morebits.wiki.preview **************** */ /** * Use the API to parse a fragment of wikitext and render it as HTML. * * The suggested implementation pattern (in {@link Morebits.simpleWindow} and * {@link Morebits.quickForm} situations) is to construct a * `Morebits.wiki.preview` object after rendering a `Morebits.quickForm`, and * bind the object to an arbitrary property of the form (e.g. |previewer|). * For an example, see twinklewarn.js. * * @memberof Morebits.wiki * @class * @param {HTMLElement} previewbox - The element that will contain the rendered HTML, * usually a <div> element. */ Morebits.wiki.preview = function(previewbox) { this.previewbox = previewbox; $(previewbox).addClass('morebits-previewbox').hide(); /** * Displays the preview box, and begins an asynchronous attempt * to render the specified wikitext. * * @param {string} wikitext - Wikitext to render; most things should work, including `subst:` and `~~~~`. * @param {string} [pageTitle] - Optional parameter for the page this should be rendered as being on, if omitted it is taken as the current page. * @param {string} [sectionTitle] - If provided, render the text as a new section using this as the title. * @returns {jQuery.promise} */ this.beginRender = function(wikitext, pageTitle, sectionTitle) { $(previewbox).show(); var statusspan = document.createElement('span'); previewbox.appendChild(statusspan); Morebits.status.init(statusspan); var query = { action: 'parse', prop: 'text', pst: 'true', // PST = pre-save transform; this makes substitution work properly text: wikitext, title: pageTitle || mw.config.get('wgPageName'), disablelimitreport: true, format: 'json' }; if (sectionTitle) { query.section = 'new'; query.sectiontitle = sectionTitle; } var renderApi = new Morebits.wiki.api('yükleniyor...', query, fnRenderSuccess, new Morebits.status('Önizleme')); return renderApi.post(); }; var fnRenderSuccess = function(apiobj) { var html = apiobj.getResponse().parse.text; if (!html) { apiobj.statelem.error('önizleme alınamadı ya da şablon boşaltılmıştı'); return; } previewbox.innerHTML = html; $(previewbox).find('a').attr('target', '_blank'); // this makes links open in new tab }; /** Hides the preview box and clears it. */ this.closePreview = function() { $(previewbox).empty().hide(); }; }; /* **************** Morebits.wikitext **************** */ /** * Wikitext manipulation. * * @namespace Morebits.wikitext * @memberof Morebits */ Morebits.wikitext = {}; /** * Get the value of every parameter found in the wikitext of a given template. * * @memberof Morebits.wikitext * @param {string} text - Wikitext containing a template. * @param {number} [start=0] - Index noting where in the text the template begins. * @returns {object} `{name: templateName, parameters: {key: value}}`. */ Morebits.wikitext.parseTemplate = function(text, start) { start = start || 0; var level = []; // Track of how deep we are ({{, {{{, or [[) var count = -1; // Number of parameters found var unnamed = 0; // Keep track of what number an unnamed parameter should receive var equals = -1; // After finding "=" before a parameter, the index; otherwise, -1 var current = ''; var result = { name: '', parameters: {} }; var key, value; /** * Function to handle finding parameter values. * * @param {boolean} [final=false] - Whether this is the final * parameter and we need to remove the trailing `}}`. */ function findParam(final) { // Nothing found yet, this must be the template name if (count === -1) { result.name = current.substring(2).trim(); ++count; } else { // In a parameter if (equals !== -1) { // We found an equals, so save the parameter as key: value key = current.substring(0, equals).trim(); value = final ? current.substring(equals + 1, current.length - 2).trim() : current.substring(equals + 1).trim(); result.parameters[key] = value; equals = -1; } else { // No equals, so it must be unnamed; no trim since whitespace allowed var param = final ? current.substring(equals + 1, current.length - 2) : current; if (param) { result.parameters[++unnamed] = param; ++count; } } } } for (var i = start; i < text.length; ++i) { var test3 = text.substr(i, 3); if (test3 === '{{{' || (test3 === '}}}' && level[level.length - 1] === 3)) { current += test3; i += 2; if (test3 === '{{{') { level.push(3); } else { level.pop(); } continue; } var test2 = text.substr(i, 2); // Entering a template (or link) if (test2 === '{{' || test2 === '[[') { current += test2; ++i; if (test2 === '{{') { level.push(2); } else { level.push('wl'); } continue; } // Either leaving a link or template/parser function if ((test2 === '}}' && level[level.length - 1] === 2) || (test2 === ']]' && level[level.length - 1] === 'wl')) { current += test2; ++i; level.pop(); // Find the final parameter if this really is the end if (test2 === '}}' && level.length === 0) { findParam(true); break; } continue; } if (text.charAt(i) === '|' && level.length === 1) { // Another pipe found, toplevel, so parameter coming up! findParam(); current = ''; } else if (equals === -1 && text.charAt(i) === '=' && level.length === 1) { // Equals found, toplevel equals = current.length; current += text.charAt(i); } else { // Just advance the position current += text.charAt(i); } } return result; }; /** * Adjust and manipulate the wikitext of a page. * * @class * @memberof Morebits.wikitext * @param {string} text - Wikitext to be manipulated. */ Morebits.wikitext.page = function mediawikiPage(text) { this.text = text; }; Morebits.wikitext.page.prototype = { text: '', /** * Removes links to `link_target` from the page text. * * @param {string} link_target * @returns {Morebits.wikitext.page} */ removeLink: function(link_target) { var mwTitle = mw.Title.newFromText(link_target); var namespaceID = mwTitle.getNamespaceId(); var title = mwTitle.getMainText(); var link_regex_string = ''; if (namespaceID !== 0) { link_regex_string = Morebits.namespaceRegex(namespaceID) + ':'; } link_regex_string += Morebits.pageNameRegex(title); // For most namespaces, unlink both [[User:Test]] and [[:User:Test]] // For files and categories, only unlink [[:Category:Test]]. Do not unlink [[Category:Test]] var isFileOrCategory = [6, 14].indexOf(namespaceID) !== -1; var colon = isFileOrCategory ? ':' : ':?'; var simple_link_regex = new RegExp('\\[\\[' + colon + '(' + link_regex_string + ')\\]\\]', 'g'); var piped_link_regex = new RegExp('\\[\\[' + colon + link_regex_string + '\\|(.+?)\\]\\]', 'g'); this.text = this.text.replace(simple_link_regex, '$1').replace(piped_link_regex, '$1'); return this; }, /** * Comments out images from page text; if used in a gallery, deletes the whole line. * If used as a template argument (not necessarily with `File:` prefix), the template parameter is commented out. * * @param {string} image - Image name without `File:` prefix. * @param {string} [reason] - Reason to be included in comment, alongside the commented-out image. * @returns {Morebits.wikitext.page} */ commentOutImage: function(image, reason) { var unbinder = new Morebits.unbinder(this.text); unbinder.unbind('<!--', '-->'); reason = reason ? reason + ': ' : ''; var image_re_string = Morebits.pageNameRegex(image); // Check for normal image links, i.e. [[File:Foobar.png|...]] // Will eat the whole link var links_re = new RegExp('\\[\\[' + Morebits.namespaceRegex(6) + ':\\s*' + image_re_string + '\\s*[\\|(?:\\]\\])]'); var allLinks = Morebits.string.splitWeightedByKeys(unbinder.content, '[[', ']]'); for (var i = 0; i < allLinks.length; ++i) { if (links_re.test(allLinks[i])) { var replacement = '<!-- ' + reason + allLinks[i] + ' -->'; unbinder.content = unbinder.content.replace(allLinks[i], replacement); } } // unbind the newly created comments unbinder.unbind('<!--', '-->'); // Check for gallery images, i.e. instances that must start on a new line, // eventually preceded with some space, and must include File: prefix // Will eat the whole line. var gallery_image_re = new RegExp('(^\\s*' + Morebits.namespaceRegex(6) + ':\\s*' + image_re_string + '\\s*(?:\\|.*?$|$))', 'mg'); unbinder.content = unbinder.content.replace(gallery_image_re, '<!-- ' + reason + '$1 -->'); // unbind the newly created comments unbinder.unbind('<!--', '-->'); // Check free image usages, for example as template arguments, might have the File: prefix excluded, but must be preceded by an | // Will only eat the image name and the preceding bar and an eventual named parameter var free_image_re = new RegExp('(\\|\\s*(?:[\\w\\s]+\\=)?\\s*(?:' + Morebits.namespaceRegex(6) + ':\\s*)?' + image_re_string + ')', 'mg'); unbinder.content = unbinder.content.replace(free_image_re, '<!-- ' + reason + '$1 -->'); // Rebind the content now, we are done! this.text = unbinder.rebind(); return this; }, /** * Converts uses of [[File:`image`]] to [[File:`image`|`data`]]. * * @param {string} image - Image name without File: prefix. * @param {string} data - The display options. * @returns {Morebits.wikitext.page} */ addToImageComment: function(image, data) { var image_re_string = Morebits.pageNameRegex(image); var links_re = new RegExp('\\[\\[' + Morebits.namespaceRegex(6) + ':\\s*' + image_re_string + '\\s*[\\|(?:\\]\\])]'); var allLinks = Morebits.string.splitWeightedByKeys(this.text, '[[', ']]'); for (var i = 0; i < allLinks.length; ++i) { if (links_re.test(allLinks[i])) { var replacement = allLinks[i]; // just put it at the end? replacement = replacement.replace(/\]\]$/, '|' + data + ']]'); this.text = this.text.replace(allLinks[i], replacement); } } var gallery_re = new RegExp('^(\\s*' + image_re_string + '.*?)\\|?(.*?)$', 'mg'); var newtext = '$1|$2 ' + data; this.text = this.text.replace(gallery_re, newtext); return this; }, /** * Remove all transclusions of a template from page text. * * @param {string} template - Page name whose transclusions are to be removed, * include namespace prefix only if not in template namespace. * @returns {Morebits.wikitext.page} */ removeTemplate: function(template) { var template_re_string = Morebits.pageNameRegex(template); var links_re = new RegExp('\\{\\{(?:' + Morebits.namespaceRegex(10) + ':)?\\s*' + template_re_string + '\\s*[\\|(?:\\}\\})]'); var allTemplates = Morebits.string.splitWeightedByKeys(this.text, '{{', '}}', [ '{{{', '}}}' ]); for (var i = 0; i < allTemplates.length; ++i) { if (links_re.test(allTemplates[i])) { this.text = this.text.replace(allTemplates[i], ''); } } return this; }, /** * Smartly insert a tag atop page text but after specified templates, * such as hatnotes, short description, or deletion and protection templates. * Notably, does *not* insert a newline after the tag. * * @param {string} tag - The tag to be inserted. * @param {string|string[]} regex - Templates after which to insert tag, * given as either as a (regex-valid) string or an array to be joined by pipes. * @param {string} [flags=i] - Regex flags to apply. `''` to provide no flags; * other falsey values will default to `i`. * @param {string|string[]} [preRegex] - Optional regex string or array to match * before any template matches (i.e. before `{{`), such as html comments. * @returns {Morebits.wikitext.page} */ insertAfterTemplates: function(tag, regex, flags, preRegex) { if (typeof tag === 'undefined') { throw new Error('Etiket belirtilmedi'); } // .length is only a property of strings and arrays so we // shouldn't need to check type if (typeof regex === 'undefined' || !regex.length) { throw new Error('Normal ifade belirtilmedi'); } else if (Array.isArray(regex)) { regex = regex.join('|'); } if (typeof flags !== 'string') { flags = 'i'; } if (!preRegex || !preRegex.length) { preRegex = ''; } else if (Array.isArray(preRegex)) { preRegex = preRegex.join('|'); } // Regex is extra complicated to allow for templates with // parameters and to handle whitespace properly this.text = this.text.replace( new RegExp( // leading whitespace '^\\s*' + // capture template(s) '(?:((?:\\s*' + // Pre-template regex, such as leading html comments preRegex + '|' + // begin template format '\\{\\{\\s*(?:' + // Template regex regex + // end main template name, optionally with a number // Probably remove the (?:) though ')\\d*\\s*' + // template parameters '(\\|(?:\\{\\{[^{}]*\\}\\}|[^{}])*)?' + // end template format '\\}\\})+' + // end capture '(?:\\s*\\n)?)' + // trailing whitespace '\\s*)?', flags), '$1' + tag ); return this; }, /** * Get the manipulated wikitext. * * @returns {string} */ getText: function() { return this.text; } }; /* *********** Morebits.userspaceLogger ************ */ /** * Handles logging actions to a userspace log. * Used in CSD, PROD, and XFD. * * @memberof Morebits * @class * @param {string} logPageName - Title of the subpage of the current user's log. */ Morebits.userspaceLogger = function(logPageName) { if (!logPageName) { throw new Error('günlük sayfası adı belirtilmedi'); } /** * The text to prefix the log with upon creation, defaults to empty. * * @type {string} */ this.initialText = ''; /** * The header level to use for months, defaults to 3 (`===`). * * @type {number} */ this.headerLevel = 3; this.changeTags = ''; /** * Log the entry. * * @param {string} logText - Doesn't include leading `#` or `*`. * @param {string} summaryText - Edit summary. * @returns {JQuery.Promise} */ this.log = function(logText, summaryText) { var def = $.Deferred(); if (!logText) { return def.reject(); } var page = new Morebits.wiki.page('Kullanıcı:' + mw.config.get('wgUserName') + '/' + logPageName, 'Girdi, kullanıcı alanı günlüğüne ekleniyor'); // make this '... to ' + logPageName ? page.load(function(pageobj) { // add blurb if log page doesn't exist or is blank var text = pageobj.getPageText() || this.initialText; // create monthly header if it doesn't exist already var date = new Morebits.date(pageobj.getLoadTime()); if (!date.monthHeaderRegex().exec(text)) { text += '\n\n' + date.monthHeader(this.headerLevel); } pageobj.setPageText(text + '\n' + logText); pageobj.setEditSummary(summaryText); pageobj.setChangeTags(this.changeTags); pageobj.setCreateOption('recreate'); pageobj.save(def.resolve, def.reject); }.bind(this)); return def; }; }; /* **************** Morebits.status **************** */ /** * Create and show status messages of varying urgency. * {@link Morebits.status.init|Morebits.status.init()} must be called before * any status object is created, otherwise those statuses won't be visible. * * @memberof Morebits * @class * @param {string} text - Text before the the colon `:`. * @param {string} stat - Text after the colon `:`. * @param {string} [type=status] - Determine the font color of the status * line, allowable values are: `status` (blue), `info` (green), `warn` (red), * or `error` (bold red). */ Morebits.status = function Status(text, stat, type) { this.textRaw = text; this.text = Morebits.createHtml(text); this.type = type || 'status'; this.generate(); if (stat) { this.update(stat, type); } }; /** * Specify an area for status message elements to be added to. * * @memberof Morebits.status * @param {HTMLElement} root - Usually a div element. * @throws If `root` is not an `HTMLElement`. */ Morebits.status.init = function(root) { if (!(root instanceof Element)) { throw new Error('object not an instance of Element'); } while (root.hasChildNodes()) { root.removeChild(root.firstChild); } Morebits.status.root = root; Morebits.status.errorEvent = null; }; Morebits.status.root = null; /** * @memberof Morebits.status * @param {Function} handler - Function to execute on error. * @throws When `handler` is not a function. */ Morebits.status.onError = function(handler) { if (typeof handler === 'function') { Morebits.status.errorEvent = handler; } else { throw 'Morebits.status.onError: handler is not a function'; } }; Morebits.status.prototype = { stat: null, statRaw: null, text: null, textRaw: null, type: 'status', target: null, node: null, linked: false, /** Add the status element node to the DOM */ link: function() { if (!this.linked && Morebits.status.root) { Morebits.status.root.appendChild(this.node); this.linked = true; } }, /** Remove the status element node from the DOM */ unlink: function() { if (this.linked) { Morebits.status.root.removeChild(this.node); this.linked = false; } }, /** * Update the status. * * @param {string} status - Part of status message after colon. * @param {string} type - 'status' (blue), 'info' (green), 'warn' * (red), or 'error' (bold red). */ update: function(status, type) { this.statRaw = status; this.stat = Morebits.createHtml(status); if (type) { this.type = type; if (type === 'error') { // hack to force the page not to reload when an error is output - see also Morebits.status() above Morebits.wiki.numberOfActionsLeft = 1000; // call error callback if (Morebits.status.errorEvent) { Morebits.status.errorEvent(); } // also log error messages in the browser console console.error(this.textRaw + ': ' + this.statRaw); // eslint-disable-line no-console } } this.render(); }, /** Produce the html for first part of the status message */ generate: function() { this.node = document.createElement('div'); this.node.appendChild(document.createElement('span')).appendChild(this.text); this.node.appendChild(document.createElement('span')).appendChild(document.createTextNode(': ')); this.target = this.node.appendChild(document.createElement('span')); this.target.appendChild(document.createTextNode('')); // dummy node }, /** Complete the html, for the second part of the status message */ render: function() { this.node.className = 'morebits_status_' + this.type; while (this.target.hasChildNodes()) { this.target.removeChild(this.target.firstChild); } this.target.appendChild(this.stat); this.link(); }, status: function(status) { this.update(status, 'status'); }, info: function(status) { this.update(status, 'info'); }, warn: function(status) { this.update(status, 'warn'); }, error: function(status) { this.update(status, 'error'); } }; /** * @memberof Morebits.status * @param {string} text - Before colon * @param {string} status - After colon * @returns {Morebits.status} - `status`-type (blue) */ Morebits.status.status = function(text, status) { return new Morebits.status(text, status); }; /** * @memberof Morebits.status * @param {string} text - Before colon * @param {string} status - After colon * @returns {Morebits.status} - `info`-type (green) */ Morebits.status.info = function(text, status) { return new Morebits.status(text, status, 'info'); }; /** * @memberof Morebits.status * @param {string} text - Before colon * @param {string} status - After colon * @returns {Morebits.status} - `warn`-type (red) */ Morebits.status.warn = function(text, status) { return new Morebits.status(text, status, 'warn'); }; /** * @memberof Morebits.status * @param {string} text - Before colon * @param {string} status - After colon * @returns {Morebits.status} - `error`-type (bold red) */ Morebits.status.error = function(text, status) { return new Morebits.status(text, status, 'error'); }; /** * For the action complete message at the end, create a status line without * a colon separator. * * @memberof Morebits.status * @param {string} text */ Morebits.status.actionCompleted = function(text) { var node = document.createElement('div'); node.appendChild(document.createElement('b')).appendChild(document.createTextNode(text)); node.className = 'morebits_status_info morebits_action_complete'; if (Morebits.status.root) { Morebits.status.root.appendChild(node); } }; /** * Display the user's rationale, comments, etc. Back to them after a failure, * so that they may re-use it. * * @memberof Morebits.status * @param {string} comments * @param {string} message */ Morebits.status.printUserText = function(comments, message) { var p = document.createElement('p'); p.innerHTML = message; var div = document.createElement('div'); div.className = 'toccolours'; div.style.marginTop = '0'; div.style.whiteSpace = 'pre-wrap'; div.textContent = comments; p.appendChild(div); Morebits.status.root.appendChild(p); }; /** * Simple helper function to create a simple node. * * @param {string} type - Type of HTML element. * @param {string} content - Text content. * @param {string} [color] - Font color. * @returns {HTMLElement} */ Morebits.htmlNode = function (type, content, color) { var node = document.createElement(type); if (color) { node.style.color = color; } node.appendChild(document.createTextNode(content)); return node; }; /** * Add shift-click support for checkboxes. The wikibits version * (`window.addCheckboxClickHandlers`) has some restrictions, and doesn't work * with checkboxes inside a sortable table, so let's build our own. * * @param jQuerySelector * @param jQueryContext */ Morebits.checkboxShiftClickSupport = function (jQuerySelector, jQueryContext) { var lastCheckbox = null; function clickHandler(event) { var thisCb = this; if (event.shiftKey && lastCheckbox !== null) { var cbs = $(jQuerySelector, jQueryContext); // can't cache them, obviously, if we want to support resorting var index = -1, lastIndex = -1, i; for (i = 0; i < cbs.length; i++) { if (cbs[i] === thisCb) { index = i; if (lastIndex > -1) { break; } } if (cbs[i] === lastCheckbox) { lastIndex = i; if (index > -1) { break; } } } if (index > -1 && lastIndex > -1) { // inspired by wikibits var endState = thisCb.checked; var start, finish; if (index < lastIndex) { start = index + 1; finish = lastIndex; } else { start = lastIndex; finish = index - 1; } for (i = start; i <= finish; i++) { if (cbs[i].checked !== endState) { cbs[i].click(); } } } } lastCheckbox = thisCb; return true; } $(jQuerySelector, jQueryContext).click(clickHandler); }; /* **************** Morebits.batchOperation **************** */ /** * Iterates over a group of pages (or arbitrary objects) and executes a worker function * for each. * * `setPageList(pageList)`: Sets the list of pages to work on. It should be an * array of page names strings. * * `setOption(optionName, optionValue)`: Sets a known option: * - `chunkSize` (integer): The size of chunks to break the array into (default * 50). Setting this to a small value (<5) can cause problems. * - `preserveIndividualStatusLines` (boolean): Keep each page's status element * visible when worker is complete? See note below. * * `run(worker, postFinish)`: Runs the callback `worker` for each page in the * list. The callback must call `workerSuccess` when succeeding, or * `workerFailure` when failing. If using {@link Morebits.wiki.api} or * {@link Morebits.wiki.page}, this is easily done by passing these two * functions as parameters to the methods on those objects: for instance, * `page.save(batchOp.workerSuccess, batchOp.workerFailure)`. Make sure the * methods are called directly if special success/failure cases arise. If you * omit to call these methods, the batch operation will stall after the first * chunk! Also ensure that either workerSuccess or workerFailure is called no * more than once. The second callback `postFinish` is executed when the * entire batch has been processed. * * If using `preserveIndividualStatusLines`, you should try to ensure that the * `workerSuccess` callback has access to the page title. This is no problem for * {@link Morebits.wiki.page} objects. But when using the API, please set the * |pageName| property on the {@link Morebits.wiki.api} object. * * There are sample batchOperation implementations using Morebits.wiki.page in * twinklebatchdelete.js, twinklebatchundelete.js, and twinklebatchprotect.js. * * @memberof Morebits * @class * @param {string} [currentAction] */ Morebits.batchOperation = function(currentAction) { var ctx = { // backing fields for public properties pageList: null, options: { chunkSize: 50, preserveIndividualStatusLines: false }, // internal counters, etc. statusElement: new Morebits.status(currentAction || msg('batch-starting', 'Performing batch operation')), worker: null, // function that executes for each item in pageList postFinish: null, // function that executes when the whole batch has been processed countStarted: 0, countFinished: 0, countFinishedSuccess: 0, currentChunkIndex: -1, pageChunks: [], running: false }; // shouldn't be needed by external users, but provided anyway for maximum flexibility this.getStatusElement = function() { return ctx.statusElement; }; /** * Sets the list of pages to work on. * * @param {Array} pageList - Array of objects over which you wish to execute the worker function * This is usually the list of page names (strings). */ this.setPageList = function(pageList) { ctx.pageList = pageList; }; /** * Sets a known option. * * @param {string} optionName - Name of the option: * - chunkSize (integer): The size of chunks to break the array into * (default 50). Setting this to a small value (<5) can cause problems. * - preserveIndividualStatusLines (boolean): Keep each page's status * element visible when worker is complete? * @param {number|boolean} optionValue - Value to which the option is * to be set. Should be an integer for chunkSize and a boolean for * preserveIndividualStatusLines. */ this.setOption = function(optionName, optionValue) { ctx.options[optionName] = optionValue; }; /** * Runs the first callback for each page in the list. * The callback must call workerSuccess when succeeding, or workerFailure when failing. * Runs the optional second callback when the whole batch has been processed. * * @param {Function} worker * @param {Function} [postFinish] */ this.run = function(worker, postFinish) { if (ctx.running) { ctx.statusElement.error('Toplu işlem hâlihazırda devam ediyor'); return; } ctx.running = true; ctx.worker = worker; ctx.postFinish = postFinish; ctx.countStarted = 0; ctx.countFinished = 0; ctx.countFinishedSuccess = 0; ctx.currentChunkIndex = -1; ctx.pageChunks = []; var total = ctx.pageList.length; if (!total) { ctx.statusElement.info(msg('batch-no-pages', 'sayfa belirtilmedi')); ctx.running = false; if (ctx.postFinish) { ctx.postFinish(); } return; } // chunk page list into more manageable units ctx.pageChunks = Morebits.array.chunk(ctx.pageList, ctx.options.chunkSize); // start the process Morebits.wiki.addCheckpoint(); ctx.statusElement.status('%0'); fnStartNewChunk(); }; /** * To be called by worker before it terminates successfully. * * @param {(Morebits.wiki.page|Morebits.wiki.api|string)} arg - * This should be the `Morebits.wiki.page` or `Morebits.wiki.api` object used by worker * (for the adjustment of status lines emitted by them). * If no Morebits.wiki.* object is used (e.g. you're using `mw.Api()` or something else), and * `preserveIndividualStatusLines` option is on, give the page name (string) as argument. */ this.workerSuccess = function(arg) { if (arg instanceof Morebits.wiki.api || arg instanceof Morebits.wiki.page) { // update or remove status line var statelem = arg.getStatusElement(); if (ctx.options.preserveIndividualStatusLines) { if (arg.getPageName || arg.pageName || (arg.query && arg.query.title)) { // we know the page title - display a relevant message var pageName = arg.getPageName ? arg.getPageName() : arg.pageName || arg.query.title; statelem.info(msg('batch-done-page', pageName, 'tamamlandı ([[' + pageName + ']])')); } else { // we don't know the page title - just display a generic message statelem.info(msg('done', 'tamamlandı')); } } else { // remove the status line automatically produced by Morebits.wiki.* statelem.unlink(); } } else if (typeof arg === 'string' && ctx.options.preserveIndividualStatusLines) { new Morebits.status(arg, msg('batch-done-page', arg, 'tamamlandı ([[' + arg + ']])')); } ctx.countFinishedSuccess++; fnDoneOne(); }; this.workerFailure = function() { fnDoneOne(); }; // private functions var thisProxy = this; var fnStartNewChunk = function() { var chunk = ctx.pageChunks[++ctx.currentChunkIndex]; if (!chunk) { return; // done! yay } // start workers for the current chunk ctx.countStarted += chunk.length; chunk.forEach(function(page) { ctx.worker(page, thisProxy); }); }; var fnDoneOne = function() { ctx.countFinished++; // update overall status line var total = ctx.pageList.length; if (ctx.countFinished < total) { var progress = Math.round(100 * ctx.countFinished / total); ctx.statusElement.status(msg('percent', progress, progress + '%')); // start a new chunk if we're close enough to the end of the previous chunk, and // we haven't already started the next one if (ctx.countFinished >= (ctx.countStarted - Math.max(ctx.options.chunkSize / 10, 2)) && Math.floor(ctx.countFinished / ctx.options.chunkSize) > ctx.currentChunkIndex) { fnStartNewChunk(); } } else if (ctx.countFinished === total) { var statusString = msg('batch-progress', ctx.countFinishedSuccess, ctx.countFinished, 'Tamamlandı (' + ctx.countFinishedSuccess + '/' + ctx.countFinished + ' işlem başarıyla tamamlandı)'); if (ctx.countFinishedSuccess < ctx.countFinished) { ctx.statusElement.warn(statusString); } else { ctx.statusElement.info(statusString); } if (ctx.postFinish) { ctx.postFinish(); } Morebits.wiki.removeCheckpoint(); ctx.running = false; } else { // ctx.countFinished > total // just for giggles! (well, serious debugging, actually) ctx.statusElement.warn('Tamamlandı (overshot by ' + (ctx.countFinished - total) + ')'); Morebits.wiki.removeCheckpoint(); ctx.running = false; } }; }; /** * Given a set of asynchronous functions to run along with their dependencies, * run them in an efficient sequence so that multiple functions * that don't depend on each other are triggered simultaneously. Where * dependencies exist, it ensures that the dependency functions finish running * before the dependent function runs. The values resolved by the dependencies * are made available to the dependant as arguments. * * @memberof Morebits * @class */ Morebits.taskManager = function(context) { this.taskDependencyMap = new Map(); this.failureCallbackMap = new Map(); this.deferreds = new Map(); this.allDeferreds = []; // Hack: IE doesn't support Map.prototype.values this.context = context || window; /** * Register a task along with its dependencies (tasks which should have finished * execution before we can begin this one). Each task is a function that must return * a promise. The function will get the values resolved by the dependency functions * as arguments. * * @param {Function} func - A task. * @param {Function[]} deps - Its dependencies. * @param {Function} [onFailure] - a failure callback that's run if the task or any one * of its dependencies fail. */ this.add = function(func, deps, onFailure) { this.taskDependencyMap.set(func, deps); this.failureCallbackMap.set(func, onFailure || function() {}); var deferred = $.Deferred(); this.deferreds.set(func, deferred); this.allDeferreds.push(deferred); }; /** * Run all the tasks. Multiple tasks may be run at once. * * @returns {jQuery.Promise} - Resolved if all tasks succeed, rejected otherwise. */ this.execute = function() { var self = this; // proxy for `this` for use inside functions where `this` is something else this.taskDependencyMap.forEach(function(deps, task) { var dependencyPromisesArray = deps.map(function(dep) { return self.deferreds.get(dep); }); $.when.apply(self.context, dependencyPromisesArray).then(function() { var result = task.apply(self.context, arguments); if (result === undefined) { // maybe the function threw, or it didn't return anything mw.log.error('Morebits.taskManager: task returned undefined'); self.deferreds.get(task).reject.apply(self.context, arguments); self.failureCallbackMap.get(task).apply(self.context, []); } result.then(function() { self.deferreds.get(task).resolve.apply(self.context, arguments); }, function() { // task failed self.deferreds.get(task).reject.apply(self.context, arguments); self.failureCallbackMap.get(task).apply(self.context, arguments); }); }, function() { // one or more of the dependencies failed self.failureCallbackMap.get(task).apply(self.context, arguments); }); }); return $.when.apply(null, this.allDeferreds); // resolved when everything is done! }; }; /** * A simple draggable window, now a wrapper for jQuery UI's dialog feature. * * @memberof Morebits * @class * @requires jquery.ui.dialog * @param {number} width * @param {number} height - The maximum allowable height for the content area. */ Morebits.simpleWindow = function SimpleWindow(width, height) { var content = document.createElement('div'); this.content = content; content.className = 'morebits-dialog-content'; content.id = 'morebits-dialog-content-' + Math.round(Math.random() * 1e15); this.height = height; $(this.content).dialog({ autoOpen: false, buttons: { 'Yer tutucu düğme': function() {} }, dialogClass: 'morebits-dialog', width: Math.min(parseInt(window.innerWidth, 10), parseInt(width ? width : 800, 10)), // give jQuery the given height value (which represents the anticipated height of the dialog) here, so // it can position the dialog appropriately // the 20 pixels represents adjustment for the extra height of the jQuery dialog "chrome", compared // to that of the old SimpleWindow height: height + 20, close: function(event) { // dialogs and their content can be destroyed once closed $(event.target).dialog('destroy').remove(); }, resizeStart: function() { this.scrollbox = $(this).find('.morebits-scrollbox')[0]; if (this.scrollbox) { this.scrollbox.style.maxHeight = 'none'; } }, resizeStop: function() { this.scrollbox = null; }, resize: function() { this.style.maxHeight = ''; if (this.scrollbox) { this.scrollbox.style.width = ''; } } }); var $widget = $(this.content).dialog('widget'); // delete the placeholder button (it's only there so the buttonpane gets created) $widget.find('button').each(function(key, value) { value.parentNode.removeChild(value); }); // add container for the buttons we add, and the footer links (if any) var buttonspan = document.createElement('span'); buttonspan.className = 'morebits-dialog-buttons'; var linksspan = document.createElement('span'); linksspan.className = 'morebits-dialog-footerlinks'; $widget.find('.ui-dialog-buttonpane').append(buttonspan, linksspan); // resize the scrollbox with the dialog, if one is present $widget.resizable('option', 'alsoResize', '#' + this.content.id + ' .morebits-scrollbox, #' + this.content.id); }; Morebits.simpleWindow.prototype = { buttons: [], height: 600, hasFooterLinks: false, scriptName: null, /** * Focuses the dialog. This might work, or on the contrary, it might not. * * @returns {Morebits.simpleWindow} */ focus: function() { $(this.content).dialog('moveToTop'); return this; }, /** * Closes the dialog. If this is set as an event handler, it will stop the event * from doing anything more. * * @param {event} [event] * @returns {Morebits.simpleWindow} */ close: function(event) { if (event) { event.preventDefault(); } $(this.content).dialog('close'); return this; }, /** * Shows the dialog. Calling display() on a dialog that has previously been closed * might work, but it is not guaranteed. * * @returns {Morebits.simpleWindow} */ display: function() { if (this.scriptName) { var $widget = $(this.content).dialog('widget'); $widget.find('.morebits-dialog-scriptname').remove(); var scriptnamespan = document.createElement('span'); scriptnamespan.className = 'morebits-dialog-scriptname'; scriptnamespan.textContent = this.scriptName + ' \u00B7 '; // U+00B7 MIDDLE DOT = &middot; $widget.find('.ui-dialog-title').prepend(scriptnamespan); } var dialog = $(this.content).dialog('open'); if (window.setupTooltips && window.pg && window.pg.re && window.pg.re.diff) { // tie in with NAVPOP dialog.parent()[0].ranSetupTooltipsAlready = false; window.setupTooltips(dialog.parent()[0]); } this.setHeight(this.height); // init height algorithm return this; }, /** * Sets the dialog title. * * @param {string} title * @returns {Morebits.simpleWindow} */ setTitle: function(title) { $(this.content).dialog('option', 'title', title); return this; }, /** * Sets the script name, appearing as a prefix to the title to help users determine which * user script is producing which dialog. For instance, Twinkle modules set this to "Twinkle". * * @param {string} name * @returns {Morebits.simpleWindow} */ setScriptName: function(name) { this.scriptName = name; return this; }, /** * Sets the dialog width. * * @param {number} width * @returns {Morebits.simpleWindow} */ setWidth: function(width) { $(this.content).dialog('option', 'width', width); return this; }, /** * Sets the dialog's maximum height. The dialog will auto-size to fit its contents, * but the content area will grow no larger than the height given here. * * @param {number} height * @returns {Morebits.simpleWindow} */ setHeight: function(height) { this.height = height; // from display time onwards, let the browser determine the optimum height, // and instead limit the height at the given value // note that the given height will exclude the approx. 20px that the jQuery UI // chrome has in height in addition to the height of an equivalent "classic" // Morebits.simpleWindow if (parseInt(getComputedStyle($(this.content).dialog('widget')[0], null).height, 10) > window.innerHeight) { $(this.content).dialog('option', 'height', window.innerHeight - 2).dialog('option', 'position', 'top'); } else { $(this.content).dialog('option', 'height', 'auto'); } $(this.content).dialog('widget').find('.morebits-dialog-content')[0].style.maxHeight = parseInt(this.height - 30, 10) + 'px'; return this; }, /** * Sets the content of the dialog to the given element node, usually from rendering * a {@link Morebits.quickForm}. * Re-enumerates the footer buttons, but leaves the footer links as they are. * Be sure to call this at least once before the dialog is displayed... * * @param {HTMLElement} content * @returns {Morebits.simpleWindow} */ setContent: function(content) { this.purgeContent(); this.addContent(content); return this; }, /** * Adds the given element node to the dialog content. * * @param {HTMLElement} content * @returns {Morebits.simpleWindow} */ addContent: function(content) { this.content.appendChild(content); // look for submit buttons in the content, hide them, and add a proxy button to the button pane var thisproxy = this; $(this.content).find('input[type="submit"], button[type="submit"]').each(function(key, value) { value.style.display = 'none'; var button = document.createElement('button'); button.textContent = value.hasAttribute('value') ? value.getAttribute('value') : value.textContent ? value.textContent : msg('submit', 'Sorguyu Gönder'); button.className = value.className || 'submitButtonProxy'; // here is an instance of cheap coding, probably a memory-usage hit in using a closure here button.addEventListener('click', function() { value.click(); }, false); thisproxy.buttons.push(button); }); // remove all buttons from the button pane and re-add them if (this.buttons.length > 0) { $(this.content).dialog('widget').find('.morebits-dialog-buttons').empty().append(this.buttons)[0].removeAttribute('data-empty'); } else { $(this.content).dialog('widget').find('.morebits-dialog-buttons')[0].setAttribute('data-empty', 'data-empty'); // used by CSS } return this; }, /** * Removes all contents from the dialog, barring any footer links. * * @returns {Morebits.simpleWindow} */ purgeContent: function() { this.buttons = []; // delete all buttons in the buttonpane $(this.content).dialog('widget').find('.morebits-dialog-buttons').empty(); while (this.content.hasChildNodes()) { this.content.removeChild(this.content.firstChild); } return this; }, /** * Adds a link in the bottom-right corner of the dialog. * This can be used to provide help or policy links. * For example, Twinkle's CSD module adds a link to the CSD policy page, * as well as a link to Twinkle's documentation. * * @param {string} text - Display text. * @param {string} wikiPage - Link target. * @param {boolean} [prep=false] - Set true to prepend rather than append. * @returns {Morebits.simpleWindow} */ addFooterLink: function(text, wikiPage, prep) { var $footerlinks = $(this.content).dialog('widget').find('.morebits-dialog-footerlinks'); if (this.hasFooterLinks) { var bullet = document.createElement('span'); bullet.textContent = msg('bullet-separator', ' \u2022 '); // U+2022 BULLET if (prep) { $footerlinks.prepend(bullet); } else { $footerlinks.append(bullet); } } var link = document.createElement('a'); link.setAttribute('href', mw.util.getUrl(wikiPage)); link.setAttribute('title', wikiPage); link.setAttribute('target', '_blank'); link.textContent = text; if (prep) { $footerlinks.prepend(link); } else { $footerlinks.append(link); } this.hasFooterLinks = true; return this; }, /** * Sets whether the window should be modal or not. Modal dialogs create * an overlay below the dialog but above other page elements. This * must be used (if necessary) before calling display(). * * @param {boolean} [modal=false] - If set to true, other items on the * page will be disabled, i.e., cannot be interacted with. * @returns {Morebits.simpleWindow} */ setModality: function(modal) { $(this.content).dialog('option', 'modal', modal); return this; } }; /** * Enables or disables all footer buttons on all {@link Morebits.simpleWindow}s in the current page. * This should be called with `false` when the button(s) become irrelevant (e.g. just before * {@link Morebits.status.init} is called). * This is not an instance method so that consumers don't have to keep a reference to the * original `Morebits.simpleWindow` object sitting around somewhere. Anyway, most of the time * there will only be one `Morebits.simpleWindow` open, so this shouldn't matter. * * @memberof Morebits.simpleWindow * @param {boolean} enabled */ Morebits.simpleWindow.setButtonsEnabled = function(enabled) { $('.morebits-dialog-buttons button').prop('disabled', !enabled); }; }(window, document, jQuery)); // End wrap with anonymous function /** * If this script is being executed outside a ResourceLoader context, we add some * global assignments for legacy scripts, hopefully these can be removed down the line. * * IMPORTANT NOTE: * PLEASE DO NOT USE THESE ALIASES IN NEW CODE! * Thanks. */ if (typeof arguments === 'undefined') { // typeof is here for a reason... /* global Morebits */ window.SimpleWindow = Morebits.simpleWindow; window.QuickForm = Morebits.quickForm; window.Wikipedia = Morebits.wiki; window.Status = Morebits.status; } // </nowiki> at2nwhttlgxh13v3b1h48dave1o4uxk MediaWiki:Gadget-Twinkle.js 8 29367 198565 178529 2022-08-09T21:36:17Z ToprakM 19785 javascript text/javascript /** * +-------------------------------------------------------------------------+ * | === WARNING: GLOBAL GADGET FILE === | * | Changes to this page affect many users. | * | Please discuss changes at [[WT:TW]] before editing. | * +-------------------------------------------------------------------------+ * * Imported from github [https://github.com/wikimedia-gadgets/twinkle]. * All changes should be made in the repository, otherwise they will be lost. * * ---------- * * This is AzaToth's Twinkle, the popular script sidekick for newbies, admins, and * every Wikipedian in between. Visit [[WP:TW]] for more information. */ // <nowiki> /* global Morebits */ (function (window, document, $) { // Wrap with anonymous function // Check if account is experienced enough to use Twinkle if (!Morebits.userIsInGroup('autoconfirmed') && !Morebits.userIsInGroup('confirmed')) { return; } var Twinkle = {}; window.Twinkle = Twinkle; // allow global access Twinkle.initCallbacks = []; /** * Adds a callback to execute when Twinkle has loaded. * @param {function} func * @param {string} [name] - name of module used to check if is disabled. * If name is not given, module is loaded unconditionally. */ Twinkle.addInitCallback = function twinkleAddInitCallback(func, name) { Twinkle.initCallbacks.push({ func: func, name: name }); }; Twinkle.defaultConfig = {}; /** * This holds the default set of preferences used by Twinkle. * It is important that all new preferences added here, especially admin-only ones, are also added to * |Twinkle.config.sections| in twinkleconfig.js, so they are configurable via the Twinkle preferences panel. * For help on the actual preferences, see the comments in twinkleconfig.js. * * Formerly Twinkle.defaultConfig.twinkle and Twinkle.defaultConfig.friendly */ Twinkle.defaultConfig = { // General userTalkPageMode: 'tab', dialogLargeFont: false, disabledModules: [], disabledSysopModules: [], // ARV spiWatchReport: 'yes', // Block defaultToBlock64: false, defaultToPartialBlocks: false, blankTalkpageOnIndefBlock: false, // Fluff (revert and rollback) autoMenuAfterRollback: false, openTalkPage: [ 'agf', 'norm', 'vand' ], openTalkPageOnAutoRevert: false, rollbackInPlace: false, markRevertedPagesAsMinor: [ 'vand' ], watchRevertedPages: [ 'agf', 'norm', 'vand', 'torev' ], watchRevertedExpiry: '1 month', offerReasonOnNormalRevert: true, confirmOnFluff: false, confirmOnMobileFluff: true, showRollbackLinks: [ 'diff', 'others' ], // DI (twinkleimage) notifyUserOnDeli: true, deliWatchPage: '1 month', deliWatchUser: '1 month', // Protect watchRequestedPages: 'yes', watchPPTaggedPages: 'default', watchProtectedPages: 'default', // PROD watchProdPages: '1 month', markProdPagesAsPatrolled: false, prodReasonDefault: '', logProdPages: false, prodLogPageName: 'BS günlüğü', // CSD speedySelectionStyle: 'buttonClick', watchSpeedyPages: [ 'g3', 'g5', 'g10', 'g11', 'g12' ], watchSpeedyExpiry: '1 month', markSpeedyPagesAsPatrolled: false, watchSpeedyUser: '1 month', // these next two should probably be identical by default welcomeUserOnSpeedyDeletionNotification: [ 'sil', 'g1', 'g2', 'g3', 'g4', 'g6', 'g10', 'g11', 'g12', 'g13', 'g14', 'a1', 'a2', 'a3', 'a5', 'a7', 'a9', 'a10', 'a11', 'f1', 'f2', 'f3', 'f7', 'f9', 'f10', 'u3', 'u5', 'p1', 'p2' ], notifyUserOnSpeedyDeletionNomination: [ 'sil', 'g1', 'g2', 'g3', 'g4', 'g6', 'g10', 'g11', 'g12', 'g13', 'g14', 'a1', 'a2', 'a3', 'a5', 'a7', 'a9', 'a10', 'a11', 'f1', 'f2', 'f3', 'f7', 'f9', 'f10', 'u3', 'u5', 'p1', 'p2' ], warnUserOnSpeedyDelete: [ 'sil', 'g1', 'g2', 'g3', 'g4', 'g6', 'g10', 'g11', 'g12', 'g13', 'g14', 'a1', 'a2', 'a3', 'a5', 'a7', 'a9', 'a10', 'a11', 'f1', 'f2', 'f3', 'f7', 'f9', 'f10', 'u3', 'u5', 'p1', 'p2' ], promptForSpeedyDeletionSummary: [], deleteTalkPageOnDelete: true, deleteRedirectsOnDelete: true, deleteSysopDefaultToDelete: false, speedyWindowHeight: 500, speedyWindowWidth: 800, logSpeedyNominations: false, speedyLogPageName: 'HS günlüğü', noLogOnSpeedyNomination: [ 'g6' ], //Buradaki u1 -> g6 ve yukarıdaki db -> sil güncellemelerinden başka değişiklik yapılmadı. // Unlink unlinkNamespaces: [ '0', '10', '100', '118' ], // Warn defaultWarningGroup: '11', combinedSingletMenus: false, showSharedIPNotice: true, watchWarnings: '1 month', oldSelect: false, customWarningList: [], // XfD logXfdNominations: false, xfdLogPageName: 'SAS günlüğü', noLogOnXfdNomination: [], xfdWatchDiscussion: 'default', xfdWatchList: 'no', xfdWatchPage: '1 month', xfdWatchUser: '1 month', xfdWatchRelated: '1 month', markXfdPagesAsPatrolled: true, // Hidden preferences autolevelStaleDays: 3, // Huggle is 3, CBNG is 2 revertMaxRevisions: 50, // intentionally limited batchMax: 5000, batchChunks: 50, // Deprecated options, as a fallback for add-on scripts/modules summaryAd: ' ([[VS:TW|TW]])', deletionSummaryAd: ' ([[VS:TW|TW]])', protectionSummaryAd: ' ([[VS:TW|TW]])', // Formerly defaultConfig.friendly: // Tag groupByDefault: true, watchTaggedVenues: ['articles', 'drafts', 'redirects', 'files'], watchTaggedPages: '1 month', watchMergeDiscussions: '1 month', markTaggedPagesAsMinor: false, markTaggedPagesAsPatrolled: true, tagArticleSortOrder: 'cat', customTagList: [], customFileTagList: [], customRedirectTagList: [], // Welcome topWelcomes: false, watchWelcomes: '3 months', insertUsername: true, quickWelcomeMode: 'norm', quickWelcomeTemplate: 'welcome', customWelcomeList: [], customWelcomeSignature: true, // Talkback markTalkbackAsMinor: true, insertTalkbackSignature: true, // always sign talkback templates talkbackHeading: mw.config.get('wgUserName') + ' adlı kullanıcıdan yeni bir mesaj', mailHeading: "E-postanız var!", // Shared markSharedIPAsMinor: true }; // now some skin dependent config. switch (mw.config.get('skin')) { case 'vector': case 'vector-2022': Twinkle.defaultConfig.portletArea = 'right-navigation'; Twinkle.defaultConfig.portletId = 'p-twinkle'; Twinkle.defaultConfig.portletName = 'TW'; Twinkle.defaultConfig.portletType = 'menu'; Twinkle.defaultConfig.portletNext = 'p-search'; break; case 'timeless': Twinkle.defaultConfig.portletArea = '#page-tools .sidebar-inner'; Twinkle.defaultConfig.portletId = 'p-twinkle'; Twinkle.defaultConfig.portletName = 'Twinkle'; Twinkle.defaultConfig.portletType = null; Twinkle.defaultConfig.portletNext = 'p-userpagetools'; break; default: Twinkle.defaultConfig.portletArea = null; Twinkle.defaultConfig.portletId = 'p-cactions'; Twinkle.defaultConfig.portletName = null; Twinkle.defaultConfig.portletType = null; Twinkle.defaultConfig.portletNext = null; } Twinkle.getPref = function twinkleGetPref(name) { if (typeof Twinkle.prefs === 'object' && Twinkle.prefs[name] !== undefined) { return Twinkle.prefs[name]; } // Old preferences format, used before twinkleoptions.js was a thing if (typeof window.TwinkleConfig === 'object' && window.TwinkleConfig[name] !== undefined) { return window.TwinkleConfig[name]; } if (typeof window.FriendlyConfig === 'object' && window.FriendlyConfig[name] !== undefined) { return window.FriendlyConfig[name]; } return Twinkle.defaultConfig[name]; }; /** * **************** Twinkle.addPortlet() **************** * * Adds a portlet menu to one of the navigation areas on the page. * This is necessarily quite a hack since skins, navigation areas, and * portlet menu types all work slightly different. * * Available navigation areas depend on the skin used. * Vector: * For each option, the outer nav class contains "vector-menu", the inner div class is "vector-menu-content", and the ul is "vector-menu-content-list" * "mw-panel", outer nav class contains "vector-menu-portal". Existing portlets/elements: "p-logo", "p-navigation", "p-interaction", "p-tb", "p-coll-print_export" * "left-navigation", outer nav class contains "vector-menu-tabs" or "vector-menu-dropdown". Existing portlets: "p-namespaces", "p-variants" (menu) * "right-navigation", outer nav class contains "vector-menu-tabs" or "vector-menu-dropdown". Existing portlets: "p-views", "p-cactions" (menu), "p-search" * Special layout of p-personal portlet (part of "head") through specialized styles. * Monobook: * "column-one", outer nav class "portlet", inner div class "pBody". Existing portlets: "p-cactions", "p-personal", "p-logo", "p-navigation", "p-search", "p-interaction", "p-tb", "p-coll-print_export" * Special layout of p-cactions and p-personal through specialized styles. * Modern: * "mw_contentwrapper" (top nav), outer nav class "portlet", inner div class "pBody". Existing portlets or elements: "p-cactions", "mw_content" * "mw_portlets" (sidebar), outer nav class "portlet", inner div class "pBody". Existing portlets: "p-navigation", "p-search", "p-interaction", "p-tb", "p-coll-print_export" * * @param String navigation -- id of the target navigation area (skin dependant, on vector either of "left-navigation", "right-navigation", or "mw-panel") * @param String id -- id of the portlet menu to create, preferably start with "p-". * @param String text -- name of the portlet menu to create. Visibility depends on the class used. * @param String type -- type of portlet. Currently only used for the vector non-sidebar portlets, pass "menu" to make this portlet a drop down menu. * @param Node nextnodeid -- the id of the node before which the new item should be added, should be another item in the same list, or undefined to place it at the end. * * @return Node -- the DOM node of the new item (a DIV element) or null */ Twinkle.addPortlet = function(navigation, id, text, type, nextnodeid) { // sanity checks, and get required DOM nodes var root = document.getElementById(navigation) || document.querySelector(navigation); if (!root) { return null; } var item = document.getElementById(id); if (item) { if (item.parentNode && item.parentNode === root) { return item; } return null; } var nextnode; if (nextnodeid) { nextnode = document.getElementById(nextnodeid); } // verify/normalize input var skin = mw.config.get('skin'); if ((skin !== 'vector' && skin !== 'vector-2022') || (navigation !== 'left-navigation' && navigation !== 'right-navigation')) { type = null; // menu supported only in vector's #left-navigation & #right-navigation } var outerNavClass, innerDivClass; switch (skin) { case 'vector': case 'vector-2022': // XXX: portal doesn't work if (navigation !== 'portal' && navigation !== 'left-navigation' && navigation !== 'right-navigation') { navigation = 'mw-panel'; } outerNavClass = 'mw-portlet vector-menu vector-menu-' + (navigation === 'mw-panel' ? 'portal' : type === 'menu' ? 'dropdown vector-menu-dropdown-noicon' : 'tabs'); innerDivClass = 'vector-menu-content'; break; case 'modern': if (navigation !== 'mw_portlets' && navigation !== 'mw_contentwrapper') { navigation = 'mw_portlets'; } outerNavClass = 'portlet'; break; case 'timeless': outerNavClass = 'mw-portlet'; innerDivClass = 'mw-portlet-body'; break; default: navigation = 'column-one'; outerNavClass = 'portlet'; break; } // Build the DOM elements. var outerNav = document.createElement('nav'); outerNav.setAttribute('aria-labelledby', id + '-label'); outerNav.className = outerNavClass + ' emptyPortlet'; outerNav.id = id; if (nextnode && nextnode.parentNode === root) { root.insertBefore(outerNav, nextnode); } else { root.appendChild(outerNav); } var h3 = document.createElement('h3'); h3.id = id + '-label'; var ul = document.createElement('ul'); if (skin === 'vector' || skin === 'vector-2022') { ul.className = 'vector-menu-content-list'; h3.className = 'vector-menu-heading'; // add invisible checkbox to keep menu open when clicked // similar to the p-cactions ("More") menu if (outerNavClass.indexOf('vector-menu-dropdown') !== -1) { var chkbox = document.createElement('input'); chkbox.className = 'vector-menu-checkbox'; chkbox.setAttribute('type', 'checkbox'); chkbox.setAttribute('aria-labelledby', id + '-label'); outerNav.appendChild(chkbox); // Vector gets its title in a span; all others except // timeless have no title, and it has no span var span = document.createElement('span'); span.appendChild(document.createTextNode(text)); h3.appendChild(span); var a = document.createElement('a'); a.href = '#'; $(a).click(function(e) { e.preventDefault(); }); h3.appendChild(a); } } else { // Basically just Timeless h3.appendChild(document.createTextNode(text)); } outerNav.appendChild(h3); if (innerDivClass) { var innerDiv = document.createElement('div'); innerDiv.className = innerDivClass; innerDiv.appendChild(ul); outerNav.appendChild(innerDiv); } else { outerNav.appendChild(ul); } return outerNav; }; /** * **************** Twinkle.addPortletLink() **************** * Builds a portlet menu if it doesn't exist yet, and add the portlet link. * @param task: Either a URL for the portlet link or a function to execute. */ Twinkle.addPortletLink = function(task, text, id, tooltip) { if (Twinkle.getPref('portletArea') !== null) { Twinkle.addPortlet(Twinkle.getPref('portletArea'), Twinkle.getPref('portletId'), Twinkle.getPref('portletName'), Twinkle.getPref('portletType'), Twinkle.getPref('portletNext')); } var link = mw.util.addPortletLink(Twinkle.getPref('portletId'), typeof task === 'string' ? task : '#', text, id, tooltip); $('.client-js .skin-vector #p-cactions').css('margin-right', 'initial'); if (typeof task === 'function') { $(link).click(function (ev) { task(); ev.preventDefault(); }); } if ($.collapsibleTabs) { $.collapsibleTabs.handleResize(); } return link; }; /** * **************** General initialization code **************** */ var scriptpathbefore = mw.util.wikiScript('index') + '?title=', scriptpathafter = '&action=raw&ctype=text/javascript&happy=yes'; // Retrieve the user's Twinkle preferences $.ajax({ url: scriptpathbefore + 'Kullanıcı:' + encodeURIComponent(mw.config.get('wgUserName')) + '/twinkleoptions.js' + scriptpathafter, dataType: 'text' }) .fail(function () { mw.notify('Twinkle tercihleriniz yüklenemedi, varsayılan tercihlere başvuruluyor'); }) .done(function (optionsText) { // Quick pass if user has no options if (optionsText === '') { return; } // Twinkle options are basically a JSON object with some comments. Strip those: optionsText = optionsText.replace(/(?:^(?:\/\/[^\n]*\n)*\n*|(?:\/\/[^\n]*(?:\n|$))*$)/g, ''); // First version of options had some boilerplate code to make it eval-able -- strip that too. This part may become obsolete down the line. if (optionsText.lastIndexOf('window.Twinkle.prefs = ', 0) === 0) { optionsText = optionsText.replace(/(?:^window.Twinkle.prefs = |;\n*$)/g, ''); } try { var options = JSON.parse(optionsText); if (options) { if (options.twinkle || options.friendly) { // Old preferences format Twinkle.prefs = $.extend(options.twinkle, options.friendly); } else { Twinkle.prefs = options; } // v2 established after unification of Twinkle/Friendly objects Twinkle.prefs.optionsVersion = Twinkle.prefs.optionsVersion || 1; } } catch (e) { mw.notify('Twinkle tercihleriniz ayrıştırılamadı', {type: 'error'}); } }) .always(function () { $(Twinkle.load); }); // Developers: you can import custom Twinkle modules here // For example, mw.loader.load(scriptpathbefore + "User:UncleDouggie/morebits-test.js" + scriptpathafter); Twinkle.load = function () { // Don't activate on special pages other than those listed here, so // that others load faster, especially the watchlist. var activeSpecialPageList = [ 'Block', 'Contributions', 'Recentchanges', 'Recentchangeslinked' ]; // wgRelevantUserName defined for non-sysops on Special:Block if (Morebits.userIsSysop) { activeSpecialPageList = activeSpecialPageList.concat([ 'DeletedContributions', 'Prefixindex' ]); } if (mw.config.get('wgNamespaceNumber') === -1 && activeSpecialPageList.indexOf(mw.config.get('wgCanonicalSpecialPageName')) === -1) { return; } // Prevent clickjacking if (window.top !== window.self) { return; } // Set custom Api-User-Agent header, for server-side logging purposes Morebits.wiki.api.setApiUserAgent('Twinkle (' + mw.config.get('wgWikiID') + ')'); Twinkle.disabledModules = Twinkle.getPref('disabledModules').concat(Twinkle.getPref('disabledSysopModules')); // Redefine addInitCallback so that any modules being loaded now on are directly // initialised rather than added to initCallbacks array Twinkle.addInitCallback = function(func, name) { if (!name || Twinkle.disabledModules.indexOf(name) === -1) { func(); } }; // Initialise modules that were saved in initCallbacks array Twinkle.initCallbacks.forEach(function(module) { Twinkle.addInitCallback(module.func, module.name); }); // Increases text size in Twinkle dialogs, if so configured if (Twinkle.getPref('dialogLargeFont')) { mw.util.addCSS('.morebits-dialog-content, .morebits-dialog-footerlinks { font-size: 100% !important; } ' + '.morebits-dialog input, .morebits-dialog select, .morebits-dialog-content button { font-size: inherit !important; }'); } // Hide the lingering space if the TW menu is empty var isVector = mw.config.get('skin') === 'vector' || mw.config.get('skin') === 'vector-2022'; if (isVector && Twinkle.getPref('portletType') === 'menu' && $('#p-twinkle').length === 0) { $('#p-cactions').css('margin-right', 'initial'); } }; /** * Twinkle-specific data shared by multiple modules * Likely customized per installation */ // Custom change tag(s) to be applied to all Twinkle actions, create at Special:Tags Twinkle.changeTags = 'twinkle'; // Available for actions that don't (yet) support tags // currently: FlaggedRevs and PageTriage Twinkle.summaryAd = ' ([[VS:TW|TW]])'; // Various hatnote templates, used when tagging (csd/xfd/tag/prod/protect) to // ensure MOS:ORDER Twinkle.hatnoteRegex = 'short description|kısa açıklama|hatnote|[İi]lknot|main|ana|correct title|doğru madde adı|dablink|distinguish|karıştırma|for|[İi]çin|further|daha fazla|selfref|year dab|similar names|highway detail hatnote|broader|about(?:-distinguish| other people)?|hakkında||other\\s?(?:hurricane(?: use)?s|people|persons|places|ships|uses(?: of)?)|redirect(?:-(?:distinguish|synonym|multi))?||yönlendirme|see\\s?(?:wiktionary|also(?: if exists)?)'; // Used in XFD and PROD Twinkle.makeFindSourcesDiv = function makeSourcesDiv(divID) { if (!$(divID).length) { return; } if (!Twinkle.findSources) { var parser = new Morebits.wiki.preview($(divID)[0]); parser.beginRender('({{Kaynak ara|' + Morebits.pageNameNorm + '}})', 'VS:SAS').then(function() { // Save for second-time around Twinkle.findSources = parser.previewbox.innerHTML; $(divID).removeClass('morebits-previewbox'); }); } else { $(divID).html(Twinkle.findSources); } }; /** Twinkle-specific utility functions shared by multiple modules */ // Used in batch, unlink, and deprod to sort pages by namespace, as // json formatversion=2 sorts by pageid instead (#1251) Twinkle.sortByNamespace = function(first, second) { return first.ns - second.ns || (first.title > second.title ? 1 : -1); }; // Used in batch listings to link to the page in question with > Twinkle.generateArrowLinks = function (checkbox) { var link = Morebits.htmlNode('a', ' >'); link.setAttribute('class', 'tw-arrowpage-link'); link.setAttribute('href', mw.util.getUrl(checkbox.value)); link.setAttribute('target', '_blank'); checkbox.nextElementSibling.append(link); }; // Used in deprod and unlink listings to link the page title Twinkle.generateBatchPageLinks = function (checkbox) { var $checkbox = $(checkbox); var link = Morebits.htmlNode('a', $checkbox.val()); link.setAttribute('class', 'tw-batchpage-link'); link.setAttribute('href', mw.util.getUrl($checkbox.val())); link.setAttribute('target', '_blank'); $checkbox.next().prepend([link, ' ']); }; }(window, document, jQuery)); // End wrap with anonymous function // </nowiki> i7myrs91ly2f2qijt7zxcghqyonsi1k MediaWiki:Gadget-friendlywelcome.js 8 29378 198566 169153 2022-08-09T21:37:01Z ToprakM 19785 javascript text/javascript // <nowiki> (function($) { /* **************************************** *** friendlywelcome.js: Karşılama / Hoş geldin modülü **************************************** * Çağırma modu: Sekme ("Karşıla") veya fark sayfalarındaki bağlantılar * Etkin olduğu yerler: Kullanıcıyla ilgili herhangi bir sayfa (kullanıcı sayfası, * katkılar vb.) ve fark sayfaları */ Twinkle.welcome = function friendlywelcome() { if (mw.util.getParamValue('friendlywelcome')) { if (mw.util.getParamValue('friendlywelcome') === 'auto') { Twinkle.welcome.auto(); } else { Twinkle.welcome.semiauto(); } } else { Twinkle.welcome.normal(); } }; Twinkle.welcome.auto = function() { if (mw.util.getParamValue('action') !== 'edit') { // userpage not empty, aborting auto-welcome return; } Twinkle.welcome.welcomeUser(); }; Twinkle.welcome.semiauto = function() { Twinkle.welcome.callback(mw.config.get('wgRelevantUserName')); }; Twinkle.welcome.normal = function() { if (mw.util.getParamValue('diff')) { // check whether the contributors' talk pages exist yet var $oList = $('#mw-diff-otitle2').find('span.mw-usertoollinks a.new:contains(talk)').first(); var $nList = $('#mw-diff-ntitle2').find('span.mw-usertoollinks a.new:contains(talk)').first(); if ($oList.length > 0 || $nList.length > 0) { var spanTag = function(color, content) { var span = document.createElement('span'); span.style.color = color; span.appendChild(document.createTextNode(content)); return span; }; var welcomeNode = document.createElement('strong'); var welcomeLink = document.createElement('a'); welcomeLink.appendChild(spanTag('Black', '[')); welcomeLink.appendChild(spanTag('Goldenrod', 'welcome')); welcomeLink.appendChild(spanTag('Black', ']')); welcomeNode.appendChild(welcomeLink); if ($oList.length > 0) { var oHref = $oList.attr('href'); var oWelcomeNode = welcomeNode.cloneNode(true); oWelcomeNode.firstChild.setAttribute('href', oHref + '&' + $.param({ friendlywelcome: Twinkle.getPref('quickWelcomeMode') === 'auto' ? 'auto' : 'norm', vanarticle: Morebits.pageNameNorm })); $oList[0].parentNode.parentNode.appendChild(document.createTextNode(' ')); $oList[0].parentNode.parentNode.appendChild(oWelcomeNode); } if ($nList.length > 0) { var nHref = $nList.attr('href'); var nWelcomeNode = welcomeNode.cloneNode(true); nWelcomeNode.firstChild.setAttribute('href', nHref + '&' + $.param({ friendlywelcome: Twinkle.getPref('quickWelcomeMode') === 'auto' ? 'auto' : 'norm', vanarticle: Morebits.pageNameNorm })); $nList[0].parentNode.parentNode.appendChild(document.createTextNode(' ')); $nList[0].parentNode.parentNode.appendChild(nWelcomeNode); } } } // Users and IPs but not IP ranges if (mw.config.exists('wgRelevantUserName') && !Morebits.ip.isRange(mw.config.get('wgRelevantUserName'))) { Twinkle.addPortletLink(function() { Twinkle.welcome.callback(mw.config.get('wgRelevantUserName')); }, 'Karşıla', 'friendly-welcome', 'Kullanıcı karşılama'); } }; Twinkle.welcome.welcomeUser = function welcomeUser() { Morebits.status.init(document.getElementById('mw-content-text')); $('#catlinks').remove(); var params = { template: Twinkle.getPref('quickWelcomeTemplate'), article: mw.util.getParamValue('vanarticle') || '', mode: 'auto' }; var userTalkPage = mw.config.get('wgFormattedNamespaces')[3] + ':' + mw.config.get('wgRelevantUserName'); Morebits.wiki.actionCompleted.redirect = userTalkPage; Morebits.wiki.actionCompleted.notice = 'Karşılama tamamlandı, mesaj sayfası birkaç saniye içinde yeniden yükleniyor'; var wikipedia_page = new Morebits.wiki.page(userTalkPage, 'Kullanıcı mesaj sayfası değişikliği'); wikipedia_page.setFollowRedirect(true); wikipedia_page.setCallbackParameters(params); wikipedia_page.load(Twinkle.welcome.callbacks.main); }; Twinkle.welcome.callback = function friendlywelcomeCallback(uid) { if (uid === mw.config.get('wgUserName') && !confirm('Kendini karşılamak istediğinden gerçekten emin misin?...')) { return; } var Window = new Morebits.simpleWindow(600, 420); Window.setTitle('Kullanıcı karşılama'); Window.setScriptName('Twinkle'); // Window.addFooterLink('Welcoming Committee', 'WP:WC'); // karşılama komitemiz yok Window.addFooterLink('Karşılama tercihleri', 'VP:TW/T#welcome'); Window.addFooterLink('Twinkle yardımı', 'VP:TW#welcome'); //Window.addFooterLink('Give feedback', 'WT:TW'); var form = new Morebits.quickForm(Twinkle.welcome.callback.evaluate); form.append({ type: 'select', name: 'type', label: 'Karşılama türü:', event: Twinkle.welcome.populateWelcomeList, list: [ { type: 'option', value: 'standard', label: 'Standart karşılamalar', selected: !mw.util.isIPAddress(mw.config.get('wgRelevantUserName')) }, { type: 'option', value: 'anonymous', label: 'Anonim kullanıcı karşılamaları', selected: mw.util.isIPAddress(mw.config.get('wgRelevantUserName')) }, { type: 'option', value: 'wikiProject', label: 'Vikiproje karşılamaları' }, { type: 'option', value: 'nonTurkish', label: 'Türkçe olmayan karşılamalar' } ] }); form.append({ type: 'div', id: 'welcomeWorkArea', className: 'morebits-scrollbox' }); form.append({ type: 'input', name: 'article', label: '* Bağlantılı madde (şablon tarafından destekleniyorsa):', value: mw.util.getParamValue('vanarticle') || '', tooltip: 'Şablon tarafından destekleniyorsa karşılama şablonundan bir maddeye bağlantı verilebilir. Bağlantılı madde olmaması için boş bırakın. Madde bağlantısını destekleyen şablonlar yıldız işaretiyle gösterilir.' }); var previewlink = document.createElement('a'); $(previewlink).click(function() { Twinkle.welcome.callbacks.preview(result); // |result| is defined below }); previewlink.style.cursor = 'pointer'; previewlink.textContent = 'Önizleme'; form.append({ type: 'div', name: 'welcomepreview', label: [ previewlink ] }); form.append({ type: 'submit' }); var result = form.render(); Window.setContent(result); Window.display(); // initialize the welcome list var evt = document.createEvent('Event'); evt.initEvent('change', true, true); result.type.dispatchEvent(evt); }; Twinkle.welcome.populateWelcomeList = function(e) { var type = e.target.value; var container = new Morebits.quickForm.element({ type: 'fragment' }); if ((type === 'standard' || type === 'anonymous') && Twinkle.getPref('customWelcomeList').length) { container.append({ type: 'header', label: 'Özel karşılama şablonları' }); container.append({ type: 'radio', name: 'template', list: Twinkle.getPref('customWelcomeList'), event: function() { e.target.form.article.disabled = false; } }); } var sets = Twinkle.welcome.templates[type]; $.each(sets, function(label, templates) { container.append({ type: 'header', label: label }); container.append({ type: 'radio', name: 'template', list: $.map(templates, function(properties, template) { return { value: template, label: '{{' + template + '}}: ' + properties.description + (properties.linkedArticle ? '\u00A0*' : ''), // U+00A0 NO-BREAK SPACE tooltip: properties.tooltip // may be undefined }; }), event: function(ev) { ev.target.form.article.disabled = !templates[ev.target.value].linkedArticle; } }); }); var rendered = container.render(); $(e.target.form).find('div#welcomeWorkArea').empty().append(rendered); var firstRadio = e.target.form.template[0]; firstRadio.checked = true; var vals = sets[Object.keys(sets)[0]]; e.target.form.article.disabled = vals[firstRadio.value] ? !vals[firstRadio.value].linkedArticle : true; }; // A list of welcome templates and their properties and syntax // The four fields that are available are "description", "linkedArticle", "syntax", and "tooltip". // The three magic words that can be used in the "syntax" field are: // - $USERNAME$ - replaced by the welcomer's username, depending on user's preferences // - $ARTICLE$ - replaced by an article name, if "linkedArticle" is true // - $HEADER$ - adds a level 2 header (most templates already include this) Twinkle.welcome.templates = { standard: { 'Genel karşılama şablonları': { "hoş geldin 1": { description: "sade karşılama", linkedArticle: false, syntax: "{{yk:hg1}} ~~~~" }, "hoş geldin 2": { description: "kutulu karşılama", linkedArticle: false, syntax: "{{yk:hg2}} ~~~~" }, "hoş geldin 3": { description: "renkli tablolu karşılama", linkedArticle: false, syntax: "{{yk:hg3}} ~~~~" }, "hoş geldin 4": { description: "ayrıntılı karşılama", linkedArticle: false, syntax: "{{yk:hg4}} ~~~~" }, "hoş geldin-kısa": { description: "kısa karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-kısa}}" }, "hoş geldin-video": { description: "beş temel taş hakkında bilgi veren bir video ile karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-video}}" }, "hoş geldin-kişisel": { description: "bir tabak kurabiye içeren daha sıcak bir karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-kişisel|$USERNAME$}}" }, "hoş geldin-gecikmiş": { description: "önemli katkıları olan kullanıcılara geç karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-gecikmiş|$USERNAME$}}" } }, 'Problem yaratan kullanıcılara yönelik şablonlar': { "hoş geldin-politika": { description: "politikalar, telif hakkı ve vandalizm hakkında bilgi veren karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-politika}}" }, "hoş geldin-ilk madde": { description: "ilk maddesi sayfa standartlarına uymayanlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-ilk madde|$ARTICLE$}}" }, "hoş geldin-deneme": { description: "ilk değişiklikleri deneme amaçlı görünenler için karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-deneme}}" }, "hoş geldin-vandal": { description: "ilk değişiklikleri vandalizm gibi görünenler için karşılama", linkedArticle: false, syntax: "{{yk:hoş geldin-vandal}}" }, "hoş geldin-reklam": { description: "ilk değişiklikleri reklam gibi görülenler için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-reklam|$ARTICLE$}}" }, "hoş geldin-kaynaksız": { description: "ilk değişiklikleri kaynaksız olanlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-kaynaksız|$ARTICLE$}}" }, "hoş geldin-sil": { description: "ilk değişikliklerinde maddelerden bilgi çıkaranlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-sil|$ARTICLE$}}" } } }, anonymous: { 'Anonim kullanıcıları karşılama şablonları': { "hoş geldin-anon": { description: "standart anonim kullanıcı karşılaması", linkedArticle: false, syntax: "{{kopyala:Anonim hoş geldin}}" }, "hoş geldin-anon-deneme": { description: "deneme değişiklikleri yapmış olanlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-anon-deneme|$ARTICLE$|$USERNAME$}}" }, "hoş geldin-anon-yararsız": { description: "yararsız değişiklikler yapmış olanlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-anon-yararsız|$ARTICLE$|$USERNAME$}}" }, "hoş geldin-anon-yapıcı": { description: "vandalizmle savaşan ve yapıcı katkıları olanlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-anon-yapıcı|art=$ARTICLE$}}" }, "hoş geldin-anon-sil": { description: "sayfalardan nedensizce içerik kaldıranlar için karşılama", linkedArticle: true, syntax: "{{yk:hoş geldin-anon-sil|$ARTICLE$|$USERNAME$}}" } } }, wikiProject: { 'Vikiprojelerle ilgili karşılama şablonları': { "hoş geldin-Vikiproje Havacılık": { description: "havacılık odaklı katkı yapanları karşılama şablonu", linkedArticle: false, syntax: "{{yk:Hoş geldin-Vikiproje Havacılık}}" }, "hoş geldin-Vikiproje Psikoloji": { description: "psikoloji odaklı katkı yapanları karşılama şablonu", linkedArticle: false, syntax: "{{yk:Hoş geldin-Vikiproje Psikoloji}}" }, "hoş geldin-Vikiproje Tarih": { description: "tarih odaklı katkı yapanları karşılama şablonu", linkedArticle: false, syntax: "{{yk:Hoş geldin-Vikiproje Tarih}}" } } }, nonTurkish: { 'Türkçe bilmeyen kullanıcıları karşılama şablonları': { "hoş geldin-en": { description: "anadili İngilizce olanlar için karşılama şablonu", linkedArticle: false, syntax: "{{kopyala:hoş geldin-en}}" } } } }; Twinkle.welcome.getTemplateWikitext = function(type, template, article) { // the iteration is required as the type=standard has two groups var properties; $.each(Twinkle.welcome.templates[type], function(label, templates) { properties = templates[template]; if (properties) { return false; // break } }); if (properties) { return properties.syntax. replace('$USERNAME$', Twinkle.getPref('insertUsername') ? mw.config.get('wgUserName') : ''). replace('$ARTICLE$', article ? article : ''). replace(/\$HEADER\$\s*/, '== Welcome ==\n\n'). replace('$EXTRA$', ''); // EXTRA is not implemented yet } return '{{yk:' + template + (article ? '|art=' + article : '') + '}}' + (Twinkle.getPref('customWelcomeSignature') ? ' ~~~~' : ''); }; Twinkle.welcome.callbacks = { preview: function(form) { var previewDialog = new Morebits.simpleWindow(750, 400); previewDialog.setTitle('Karşılama şablonu önizlemesi'); previewDialog.setScriptName('Kullanıcı karşılama'); previewDialog.setModality(true); var previewdiv = document.createElement('div'); previewdiv.style.marginLeft = previewdiv.style.marginRight = '0.5em'; previewdiv.style.fontSize = 'small'; previewDialog.setContent(previewdiv); var previewer = new Morebits.wiki.preview(previewdiv); var input = Morebits.quickForm.getInputData(form); previewer.beginRender(Twinkle.welcome.getTemplateWikitext(input.type, input.template, input.article), 'User talk:' + mw.config.get('wgRelevantUserName')); // Force wikitext/correct username var submit = document.createElement('input'); submit.setAttribute('type', 'submit'); submit.setAttribute('value', 'Kapat'); previewDialog.addContent(submit); previewDialog.display(); $(submit).click(function() { previewDialog.close(); }); }, main: function(pageobj) { var params = pageobj.getCallbackParameters(); var text = pageobj.getPageText(); // abort if mode is auto and form is not empty if (pageobj.exists() && params.mode === 'auto') { Morebits.status.info('Uyarı', 'Kullanıcı mesaj sayfası boş değil; otomatik karşılama iptal ediliyor'); Morebits.wiki.actionCompleted.event(); return; } var welcomeText = Twinkle.welcome.getTemplateWikitext(params.type, params.template, params.article); if (Twinkle.getPref('topWelcomes')) { var hasTalkHeader = /^\{\{Tartışma\}\}/i.test(text); if (hasTalkHeader) { text = text.replace(/^\{\{Tartışma\}\}\n{0,2}/i, ''); text = '{{Tartışma}}\n\n' + welcomeText + '\n\n' + text; text = text.trim(); } else { text = welcomeText + '\n\n' + text; } } else { text += '\n' + welcomeText; } var summaryText = 'Vikipedi\'ye hoş geldiniz!'; pageobj.setPageText(text); pageobj.setEditSummary(summaryText); pageobj.setChangeTags(Twinkle.changeTags); pageobj.setWatchlist(Twinkle.getPref('watchWelcomes')); pageobj.setCreateOption('recreate'); pageobj.save(); } }; Twinkle.welcome.callback.evaluate = function friendlywelcomeCallbackEvaluate(e) { var form = e.target; var params = Morebits.quickForm.getInputData(form); // : type, template, article params.mode = 'manual'; Morebits.simpleWindow.setButtonsEnabled(false); Morebits.status.init(form); var userTalkPage = mw.config.get('wgFormattedNamespaces')[3] + ':' + mw.config.get('wgRelevantUserName'); Morebits.wiki.actionCompleted.redirect = userTalkPage; Morebits.wiki.actionCompleted.notice = 'Karşılama tamamlandı, mesaj sayfası birkaç saniye içinde yeniden yükleniyor'; var wikipedia_page = new Morebits.wiki.page(userTalkPage, 'Kullanıcı mesaj sayfası değişikliği'); wikipedia_page.setFollowRedirect(true); wikipedia_page.setCallbackParameters(params); wikipedia_page.load(Twinkle.welcome.callbacks.main); }; Twinkle.addInitCallback(Twinkle.welcome, 'welcome'); })(jQuery); // </nowiki> o429bp0lt5hvidjiwmmo8wbkogjgqfv MediaWiki:Gadget-morebits.css 8 29388 198561 160575 2022-08-09T21:31:34Z ToprakM 19785 css text/css /** * morebits.css * =========== * Styles to support morebits.js. * * The morebits library is maintained by the maintainers of Twinkle. * For queries, suggestions, help, etc., head to [[WT:TW]]. * The latest development source is available at [https://github.com/wikimedia-gadgets/twinkle/blob/master/morebits.css]. */ /* Morebits.status */ .morebits_status_status { color: #4682B4; } .morebits_status_info { color: #228B22; } .morebits_status_warn { color: #FF4500; } .morebits_status_error { color: #FF4500; font-weight: bold; } /* Morebits.quickForm */ form.quickform { width: 96%; vertical-align: middle; margin: auto; padding: .5em; } form.quickform * { font-family: sans-serif; } form.quickform fieldset { margin: .4em 0 1em; } form.quickform legend { color: #31628F; font-weight: bold; } form.quickform input[type=text], form.quickform select { min-width: 15em; font-size: 110%; } form.quickform select { border: 1px solid gray; margin-left: .2em; } form.quickform input[type=checkbox], form.quickform input[type=radio] { height: 13px; margin-top: 2px; margin-right: 2px; margin-bottom: 2px; padding: 0; width: 13px; vertical-align: top; } form.quickform div { line-height: 18px; } form.quickform h5 { margin: .5em 0 0; padding: .3em .2em .2em; font-size: 108%; /* 100% is 12px => 108% is 12.96px */ } /* only give the top border to headers with something above them */ form.quickform div+h5, form.quickform div+div>h5, form.quickform h5+h5 { border-top: 1px solid #88A; } form.quickform textarea { width: 100%; height: 4em; font-size: 150%; } form.quickform input:disabled+label { color: gray; } form.quickform span.quickformDescription { font-style: italic; } form.quickform span.quickformDescription code { font-style: normal; font-family: monospace; } form.quickform .quickformSubgroup { margin-bottom: .5em; margin-left: 3em; } /* The tooltip button and the content itself */ form.quickform .morebits-tooltipButton { color: mediumblue; font-weight: bold; cursor: help; padding: .3em; } .morebits-ui-tooltip { padding: 4px 6px 4px 6px; font-size: 13px; } /* Scrollbox styles, for use within Morebits.simpleWindow */ div.morebits-scrollbox { background: white; border: 1px solid gray; margin-bottom: .6em; margin-top: .6em; max-height: 20em; overflow: auto; padding: 6px 6px 0; } div.morebits-scrollbox>h5:first-child { border: none; margin-top: 0; padding-top: 0; } div.morebits-scrollbox> :last-child { margin-bottom: 6px; } /* Previewbox */ div.morebits-previewbox { background: white; color: black; border: 2px inset; margin: .4em auto .2em; padding: .2em .4em; } div.morebits-previewbox *:not(img) { vertical-align: baseline; } div.morebits-previewbox .mw-editsection { display: none; } /* Morebits.simpleWindow */ .morebits-dialog { border: 1px #666 solid; font-family: sans-serif; background-color: #F0F8FF; background-image: none; } /* px translations in comments are w.r.t standard browser settings, in other settings, the sizes would be scaled accordingly */ .skin-vector .morebits-dialog { font-size: 75%; /* 100% is 16px => 75% is 12px */ } .skin-timeless .morebits-dialog { font-size: 79%; /* 100% is 15.2px => 79% is 12.008px */ } .skin-monobook .morebits-dialog, .skin-modern .morebits-dialog { font-size: 120%; /* 100% is 10px => 120% is 12px */ } body .ui-dialog.morebits-dialog .ui-dialog-titlebar { height: 1em; background-color: #BCCADF !important; background-image: none !important; font: bold 108% sans-serif; /* 100% is 12px (from above) => 108% is 12.96px */ overflow: hidden; padding: .4em .3em .5em !important; white-space: nowrap; } .morebits-dialog-scriptname { font-weight: normal; } .ui-dialog.morebits-dialog .ui-dialog-titlebar-close { height: 100%; right: 0; top: auto; width: 2em; margin: -.5em -.15em 0; } .ui-dialog.morebits-dialog .ui-dialog-titlebar-close span { margin: .33em; } .ui-dialog.morebits-dialog .morebits-dialog-content { padding: 0; } body .ui-dialog.morebits-dialog .ui-dialog-buttonpane { background-color: #BCCADF; margin: 0; min-height: .5em; padding-left: 1.2em !important; } body .ui-dialog.morebits-dialog .ui-dialog-buttonpane button { float: none; margin: .2em 0 -.1em; color: #fff; background-color: #36c; border-color: #36c; padding: 6px; line-height: 1; border-style: solid; position: relative; font-weight: bold; text-decoration: none; text-align: center; cursor: pointer; display: inline-block; box-sizing: border-box; vertical-align: middle; font-family: inherit; font-size: inherit; white-space: nowrap; user-select: none; border-radius: 3px; } .morebits-dialog-buttons { font-size: 108%; /* 100% is 12px => 108% is 12.96px */ } .morebits-dialog-footerlinks { font-size: 97%; /* 100% is 12px (from above) => 97% is 11.64px */ float: right; margin: .7em .4em 0 0; } body .ui-dialog.morebits-dialog .morebits-dialog-footerlinks a { color: #3062AD; } .morebits-dialog-buttons[data-empty]+.morebits-dialog-footerlinks { margin: .1em .4em -.2em 0; } .ui-icon { vertical-align: -3px; } .ui-icon-inline { display: inline-block; } /* For styling message/warning boxes. Cannot use MediaWiki ombox class because it will be deprecated soon. */ table.morebits-ombox { margin: 4px 10%; border-collapse: collapse; border: 1px solid #a2a9b1; background: #f8f9fa; box-sizing: border-box; } table.morebits-ombox-content { border: 1px solid #f28500; } td.morebits-mbox-image { border: none; padding: 2px 0 2px 0.9em; text-align: center; } th.morebits-mbox-text, td.morebits-mbox-text { border: none; padding: 0.25em 0.9em; width: 100%; } ftae4qq2tf2jmkwjds1nzf0tx29a1pe MediaWiki:Gadget-Twinkle.css 8 29389 198559 171513 2022-08-09T21:30:46Z ToprakM 19785 css text/css /** * Explicitly set width of TW menu so that we can use a hidden peer gadget * to add space where the TW menu would go before it loads. */ .skin-vector .vector-menu-dropdown #p-twinkle { width: 3.24em; } /* The additional box on user skin.js and twinklepreferences.js pages */ #twinkle-config-headerbox { border: 1px #f60 solid; background: #fed; padding: 0.6em; margin: 0.5em auto; text-align: center; } /* twinkleoptions.js */ #twinkle-config-headerbox.config-twopt-box { font-weight: bold; width: 80%; border-width: 2px; } /* skin-specific js */ #twinkle-config-headerbox.config-userskin-box { width: 60%; } /* WP:TWPREFS */ #twinkle-config-content input[type=checkbox] { margin-right: 2px; } fmk9xyhc56ikz605qn9tyjzp0fj6xjb Köy enstitüsü 0 35539 198551 198445 2022-08-09T20:14:14Z Modern primat 25001 Tartışma sayfasi wikitext text/x-wiki {{Vikipedi}} '''Köy enstitüsü''', Türkiye'de ilkokul öğretmeni yetiştirmek üzere 17 Nisan 1940 tarihli ve 3803 sayılı yasa ile açılan okul türü. Tamamen Türkiye'ye özgü olan bu eğitim projesini 28 Aralık 1938 tarihinde milli eğitim bakanı olan [[Hasan Âli Yücel]] bizzat yönetti. Türkiye'de köy enstitüsü fikri ilk kez [[Amerikalılar|Amerikalı]] eğitim filozofu [[John Dewey]] tarafından savunuldu.<ref>B. Güvenç, "History of Turkish Education", Educalian and Science, Vol. 22 (108), Special Issue, 1998, p. 56.</ref> Dewey, özellikle kırsal bölgelerdeki okulların toplum yaşam merkezi haline getirilmesi gerektiğini vurguladı. Türkiye'de okulun yerel koşullara uyarlanması sorunu eğitim felsefesinin özünü oluşturuyordu. Köy Enstitüleri, John Dewey'in iş ve eğitimi birleştirme fikrini yerine getirmek için tasarlanmıştır. Mezunların aynı anda hem okul öğretmenleri hem de toplumun eğitmeni olması bekleniyordu. Öğrenciler aslında kendi okullarını, evlerini, kışlalarını, iş yerlerini vb. inşa ettiler ve birlikte yaparak ve yaşayarak üretim ile eğitimi kaynaştırdılar.<ref>THE INFLUENCE OF AN AMERICAN EDUCATOR (JOHN DEWEY) ON THE Turkish educational system, THE TURKISH YEARBOOK VOL. XXXI, by BAHRİ ATA</ref><ref>''John Dewey'' (/ˈduːi/; October 20, 1859 – June 1, 1952) was an American philosopher, psychologist, and educational reformer whose ideas have been influential in education and social reform. He is regarded as one of the most prominent American scholars in the first half of the twentieth century.</ref><ref>"Profesör John Dewey'nin Raporları", Maarif Vekaleti Mecmuası, March 1925, No. I. Its Turkish translation was published several times. In 1939, during the time of Hasan Ali Yücel, Minister of Educatian, the Dewey report wa" republished.</ref><ref>{{Web kaynağı |url=http://dergiler.ankara.edu.tr/dergiler/44/671/8547.pdf |başlık=Arşivlenmiş kopya |erişimtarihi=18 Aralık 2019 |arşivurl=https://web.archive.org/web/20180722212926/http://dergiler.ankara.edu.tr/dergiler/44/671/8547.pdf |arşivtarihi=22 Temmuz 2018 |ölüurl=hayır }}</ref> ==Hakkında söylenenler== *Köy Enstitülerini Cumhuriyetin eserleri içinde en kıymetlisi ve en sevgilisi sayıyorum. Köy Enstitülerinden yetişen evlatlarımızın muvaffakiyetlerini ömrüm oldukça yakından, candan takip edeceğim.<ref>https://www.ismetinonu.org.tr/ismet-inonu-ve-koy-enstituleri/#24</ref> — [[İsmet İnönü]] *İnönü, karma eğitimde kızların okutulmasına karşı çıkılması ve ilköğretimin hızlıca halledilmesi gerektiği konularında eğitimi “'''insan olarak yaşamak için su ve hava gibi'''” doğal bir gereksinim olarak görürdü ve '''Enstitüler''' Türkiye’nin bu sorununa çözümdü.<ref name="ismetinonu.org.tr">https://www.ismetinonu.org.tr/ismet-inonu-ve-koy-enstituleri</ref> *Arkadaşlarım bu işle uğraşmak için benim bulduğum kadar vakit ve heves ayırabilirlerse, biz devam meselesini yakın zamanda tamamiyle hallederiz Bunu hallettiğimiz zaman, memleketin ve milletin az zamanda o kadar farklı ilerlemesini sağlayacak ana tedbiri nasıl bulmuş olduğumuza kendimiz de şaşakalırız.<ref name="ismetinonu.org.tr"/> — [[İsmet İnönü]] *Köy Enstitüleri hakkında ne düşündüğünü söyle kim olduğunu söyleyeyim.<ref name="ismetinonu.org.tr"/> — [[Sabahattin Eyüboğlu]] *[[Hasan Ali Yücel]], Enstitüleri “'''bir arı kovanı halinde tam bir aile görüşü ile kendi ihtiyaçlarına cevap vermek mihveri etrafında işleyen bir insan fabrikası'''”na benzetmektedir (Yücel, 1993, s. 63)<ref name="dergipark.org.tr">https://dergipark.org.tr/tr/download/article-file/255300</ref> *Köy Eğitmeni Projesi daha sonra kurulan Köy Enstitüleri için uygun ortamı hazırlamış ve Köy Enstitülerine geçişi bir nevi kolaylaştırmıştır. [[Hasan Ali Yücel]], kendisinden önce başlanan bu Köy Eğitmeni Projesiyle yetişen eğitmenlerden kırsal kesimde alınan verimin memnuniyet verici olduğunu düşünerek “'''köyden yetişmiş, köy kalkınmasının hayati ehemmiyetini içinden duymuş, çalışkan ve müteşebbis gençlerin köy çocuklarını ve köy halkını yetiştirmek için lazım olan bilgiler, maharetler, teknik vasıtalar ve bilhassa ideallerle'''” donatıldıklarını dile getirmiştir (Birinci Maarif Şurası, 1939, t.y.).<ref name="dergipark.org.tr"/> *Köy Enstitüleri ile kapalı olan köylü hazinesi keşfolunmuştur. Bunun mütehassısları cesaretle bunun içine girdiler. Başarıyı, ilk önce burada değerlendirmek lazımdır. Köy Enstitülerinde çalışanları, Hasan Ali Yücel’i , Hakkı Tonguç’u rahmetle anmak isterim. Ben Devletin başındaydım. Köy Enstitülerindin asıl zahmetini çekenler, bu eserin mimarları ve onun tutunması için çalışanlardır. Eser onlarındır.<ref name="ismetinonu.org.tr"/> — [[İsmet İnönü]] *Kanunun kabul edildiği oturuma dönemin DP mebusları muhalefet ettiler ve katılmadılar, oturumunda Kazım Karabekir'in projenin nereden alındığını sorması üzerine [[Hasan Âli Yücel]] şöyle konuşmuştur: '''Arkadaşlar bu kanunla bizim yaptığımız şey bir kopya değildir. Bunları kendi ülkemizin var olan gerçeğine ve toplumsal olgusuna uyarak yapmış bulunuyoruz. Bu bizimdir, kimseden almadık. Başkaları bizden alsınlar.'''<ref name="Keseroglu">{{Web kaynağı |url=http://www.kutuphaneci.org.tr/web/node.php?action=6&type=6&target=contentShow&id=1454&node_id=192 |başlık=Hasan Keseroğlu, Türk kütüphaneciliği, ''Köy enstitülerinde okuma ve kütüphane'', 2005 |erişimtarihi=2 Şubat 2009 |arşivurl=https://web.archive.org/web/20100124115251/http://www.kutuphaneci.org.tr/web/node.php?action=6 |arşivtarihi=24 Ocak 2010 |ölüurl=evet}}</ref> *''İsmet İnönü'ye hitaben'', Bu komünist yuvalarını ne zaman kapatacaksın? — [[Fevzi Çakmak]] *Köy Enstitülerinin kapanmasından duyduğum acıyı tarif edemem. Bir babanın evladını kaybetmesinden duyduğu acı gibi duyarım, ama herkes zanneder ki Hasan Ali Yücel’i Tonguç’u isteyerek değiştirdim; Köy Enstitülerinin kapanmasına neden oldum diye benim hakkımda kamuoyunda yanlış bir hüküm vardır; aslında o zaman bir sürü olaylar oldu. Kurultaylarda Enstitüler aleyhine bir cereyan başladı. Ben bunların doğru olmadığını yerine giderek tespit ettim, ama bu o kadar yoğunlaştı ki grubu etkiledi. Grubun büyük çoğunluğu Köy Enstitülerinin aleyhine döndü. Bakanlar içinde Köy Enstitülerine karşı vaziyet alanlar çoğaldı. En çok da bu konuda Köy Enstitülerinden şikayet edilenlerin başında Milli Eğitim Bakanı Yücel’le, Genel Müdür Tonguç hedef alınıyordu. O sırada ordudan, rahmetli [[Mareşal Fevzi Çakmak]]’tan (1876 – 1950), o Genelkurmay Başkanlığından ayrılmadan önce, yoğun şikayetler başladı. Mareşal, “ Bu komünist yuvalarını ne zaman kapatacaksın ? ” diye soruyordu. Mareşal bunu adeta bir mesele haline getirmişti. Köy Enstitüleri etrafında bu çok yoğunlaştı. :Şimdi sana önemli bir şey söyleyeceğim: Herkes benim zayıflığım gibi görür, ama benim gücümdür aslında; mesela ben Köy Enstitüsü fikrine inanmışımdır. İnanmış bir insan, sonuna kadar bunu yürütür; idealizmde, felsefede bu böyledir, ama ben politikacıyım, uygulayıcıyım. Ben gücüme göre gücümün var olduğu yerde, gücümü gösterebilirim. Ben dahi değilim, gücümle, tecrübemle memleket menfaatlerini en üst seviyede tutarak meselelere çözüm bulurum. Ben gücümün bittiği yerde bir politikacı, bir tecrübe sahibi bir insan olarak bir noktada, onu gelecekte tekrar uygulamak üzere bir noktada durdururum. Bu, aslında benim gücümdür. Çünkü artık gücümü kaybettiğim noktada, “Ben bu işi yürüteceğim !” diye yürüdüğüm zaman, artık tamamıyla yok olma durumu vardır; ben gücümün bittiği yerde, her şeye rağmen, yok olucu bir harekete yönelmem. Orada dururum. Zaman, benim için önemli bir faktördür; zaman içinde imkanlar gelir önüme, bir noktada bıraktığım fikrimi yeniden uygularım. Değişen zaman içinde de bana yeni fikirler gelmemiş, o fikrin doğruluğu bende bir kanaat olarak devam ediyorsa, onu yeniden uygularım. Köy Enstitüleri meselesi de böyle olmuştur. :Benim gücüm o zaman nereden geliyordu ? Partiden, Parti Meclis Grubundan, gücümü ben buradan alıyordum. Bu konuda bütün organlarda gücümü kaybetmişim. Ordunun üst kademesinde de huzursuzluk başlamış. Onun için bir süre en çok bu konuda saldırıya uğrayan, Milli Eğitim Bakanı Yücel’le, Genel Müdür Tonguç’u onların da gönlünü alarak bir süre için bu şimşekleri bu olay üzerinden uzaklaştırmak istedim. Fakat sonradan demokratik hareketleri de başlatınca, olaylar öyle gelişti ki kendi cereyanında yürüdü ve bir an geldi ki artık Köy Enstitülerini, eski gücüyle, eski ruhuyla devam ettirmek olanakları benim elimden çıktı. — [[İsmet İnönü]] <ref>Topraktan Parlamentoya – Muammer Erten – Boyut Yayınları 2010 sayfa: 271</ref><ref>https://www.ismetinonu.org.tr/koy-enstituleri-nicin-kapandi-1954/</ref> ==Kaynakça== {{Kaynakça}} hwrsw8uwwr56z4yn3rbq8l0rkong1or Şeriat 0 35664 198554 198531 2022-08-09T21:23:55Z ToprakM 19785 kişi maddesi değil wikitext text/x-wiki '''Şeriat''', [[İslam hukuku]] anlamında [[Kur'an]] [[âyet]]leri ile [[hadis|Muhammed'in söz ve fiilleri]]nden oluşan naslardan alimler sınıfının ([[fıkıh|Fukaha]]) çıkarımları (istinbat) ile oluşturulan dini kanunlar toplamıdır. İslam'da farz kabul edilen [[ibadet]]ler, [[yaptırım|muamele]]ler ve [[ceza]]larla ilgili tüm kavram ve kuralları kapsar. == Hakkında söylenenler == * Anlatılanlara isterseniz "roman" demeyin. "Romanlaşan gerçekler...". Edebiyattaki "edeb"li "aydın"ım bilir misin nedir "kulleteyn"? Ve bilir misin onu yaratan Şeriat nasıl bir ilkelliktir? "Türko" ise onun içinde gelişen "ölüm"ü. Bilir misin?<ref>Turan Dursun, Kulleteyn, Kaynak Yayınları, sayfa 371</ref> - [[Turan Dursun]] *Keşke Yunan galip gelseydi. Ne hilafet yıkılırdı ne şeriat kaldırılırdı ne medrese lağvedilirdi ne hocalar asılırdı. Hiçbiri olmazdı.<ref>[http://www.cumhuriyet.com.tr/video/video/783676/Kadir_Misiroglu__Keske_Yunan_galip_gelseydi.html Kadir Mısıroğlu: Keşke Yunan galip gelseydi]</ref> - [[Kadir Mısıroğlu]] *Hem kahrolsun şeriat diyorlar, hem de o pislik cenazelerini camiye getiriyorlar. '''Hem çağ dışı diyeceksin, hem cesedini çağ dışı dediğinin camisine getireceksin?''' - [[Timurtaş Uçar]] * Yeni binyılın şeyhlerinin, dervişlerinin, müritlerinin ve de meczuplarının amaçlarının da değiştiği gözlemleniyor. Artık amaç, bir şeriat devleti kurmak değil. '''Şeriat, iktidarı, parayı, her türlü gücü ele geçirmenin sadece simgesel, klişeleşmiş adı.'''<ref>Necip Hablemitoğlu. "Önsöz". ''Köstebek'', Toplumsal Dönüşüm Yayınları, s. 9.</ref> - [[Necip Hablemitoğlu]] *İki tane ayyaşın yaptığı yasa, sizin için muteber oluyor da inancın emrettiği bir gerçek, bir vakıa niçin sizler için reddedilmesi gereken bir olay hâline geliyor? - (28 Mayıs 2013 tarihinde partisinin grup toplantısında yaptığı konuşmasından), [[Recep Tayyip Erdoğan]] == Kaynakça == {{kaynakça}} {{taslak}} fg137jpndqwp66oh1lx9x7rn1tqq191 Tartışma:Köy enstitüsü 1 35666 198550 2022-08-09T20:09:21Z Modern primat 25001 /* telif hakkı */ yeni başlık wikitext text/x-wiki == telif hakkı == evet.. en başta, burada verilen kaynaklardan aldığım sözleri tek başına alınca anlamsız olduğunu düşündüm ve kaynakta verilen açıklamayı da koydum. o açıklamalar telif hakkı ihlali mi sizce? şimdiden açıklamaları kaldırmaya çalışacam.... sanırım 2-3 haftadır madde böyle duruyor.... ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 20.09, 9 Ağustos 2022 (UTC) 54mbkspao69lrd0as14logvflgrtvfn 198552 198550 2022-08-09T20:18:42Z Modern primat 25001 /* telif hakkı */ Yanıt wikitext text/x-wiki == telif hakkı == evet.. en başta, burada verilen kaynaklardan aldığım sözleri tek başına alınca anlamsız olduğunu düşündüm ve kaynakta verilen açıklamayı da koydum. o açıklamalar telif hakkı ihlali mi sizce? şimdiden açıklamaları kaldırmaya çalışacam.... sanırım 2-3 haftadır madde böyle duruyor.... ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 20.09, 9 Ağustos 2022 (UTC) :telif hakkı konusunda emin değilim...ama endişeliyim.. ah, iki tane kaldi.. bı tanesini hallettim.. :acaba?... o açıklamaları yalnızca, yine başkalarının sözü olarak mi görmek gerek? ama.... garip.... biz kayda değer olanları koymuyor muyuz? ----[[Kullanıcı:Modern primat|modern_primat]] [[Özel:Katkılar/Modern_primat|ඞඞඞ]][[m:Steward_requests/Global/2022-w23#Global_lock_for_Modern_primat|⚖️]]<sup>[[Kullanıcı mesaj:Modern primat|İLETİ]]</sup> 20.18, 9 Ağustos 2022 (UTC) fsztj9oxryq52geu3gt56mx22fsbca8 MediaWiki:Gadget-select2.min.js 8 35667 198562 2022-08-09T21:32:06Z ToprakM 19785 "// <nowiki> /*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */ !function(n){"function"==typeof define&&define.amd?define(["jquery"],n):/*"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:*/n(jQuery)}(function(u){var e=function(){if(u&&u.fn&&u.fn.select2&&u.fn.select2.amd)var e=u.fn.select2.amd;var t,n,r,h,o,s..." içeriğiyle yeni sayfa oluşturdu javascript text/javascript // <nowiki> /*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */ !function(n){"function"==typeof define&&define.amd?define(["jquery"],n):/*"object"==typeof module&&module.exports?module.exports=function(e,t){return void 0===t&&(t="undefined"!=typeof window?require("jquery"):require("jquery")(e)),n(t),t}:*/n(jQuery)}(function(u){var e=function(){if(u&&u.fn&&u.fn.select2&&u.fn.select2.amd)var e=u.fn.select2.amd;var t,n,r,h,o,s,f,g,m,v,y,_,i,a,w;function b(e,t){return i.call(e,t)}function l(e,t){var n,r,i,o,s,a,l,c,u,d,p,h=t&&t.split("/"),f=y.map,g=f&&f["*"]||{};if(e){for(s=(e=e.split("/")).length-1,y.nodeIdCompat&&w.test(e[s])&&(e[s]=e[s].replace(w,"")),"."===e[0].charAt(0)&&h&&(e=h.slice(0,h.length-1).concat(e)),u=0;u<e.length;u++)if("."===(p=e[u]))e.splice(u,1),u-=1;else if(".."===p){if(0===u||1===u&&".."===e[2]||".."===e[u-1])continue;0<u&&(e.splice(u-1,2),u-=2)}e=e.join("/")}if((h||g)&&f){for(u=(n=e.split("/")).length;0<u;u-=1){if(r=n.slice(0,u).join("/"),h)for(d=h.length;0<d;d-=1)if(i=(i=f[h.slice(0,d).join("/")])&&i[r]){o=i,a=u;break}if(o)break;!l&&g&&g[r]&&(l=g[r],c=u)}!o&&l&&(o=l,a=c),o&&(n.splice(0,a,o),e=n.join("/"))}return e}function A(t,n){return function(){var e=a.call(arguments,0);return"string"!=typeof e[0]&&1===e.length&&e.push(null),s.apply(h,e.concat([t,n]))}}function x(t){return function(e){m[t]=e}}function D(e){if(b(v,e)){var t=v[e];delete v[e],_[e]=!0,o.apply(h,t)}if(!b(m,e)&&!b(_,e))throw new Error("No "+e);return m[e]}function c(e){var t,n=e?e.indexOf("!"):-1;return-1<n&&(t=e.substring(0,n),e=e.substring(n+1,e.length)),[t,e]}function S(e){return e?c(e):[]}return e&&e.requirejs||(e?n=e:e={},m={},v={},y={},_={},i=Object.prototype.hasOwnProperty,a=[].slice,w=/\.js$/,f=function(e,t){var n,r=c(e),i=r[0],o=t[1];return e=r[1],i&&(n=D(i=l(i,o))),i?e=n&&n.normalize?n.normalize(e,function(t){return function(e){return l(e,t)}}(o)):l(e,o):(i=(r=c(e=l(e,o)))[0],e=r[1],i&&(n=D(i))),{f:i?i+"!"+e:e,n:e,pr:i,p:n}},g={require:function(e){return A(e)},exports:function(e){var t=m[e];return void 0!==t?t:m[e]={}},module:function(e){return{id:e,uri:"",exports:m[e],config:function(e){return function(){return y&&y.config&&y.config[e]||{}}}(e)}}},o=function(e,t,n,r){var i,o,s,a,l,c,u,d=[],p=typeof n;if(c=S(r=r||e),"undefined"==p||"function"==p){for(t=!t.length&&n.length?["require","exports","module"]:t,l=0;l<t.length;l+=1)if("require"===(o=(a=f(t[l],c)).f))d[l]=g.require(e);else if("exports"===o)d[l]=g.exports(e),u=!0;else if("module"===o)i=d[l]=g.module(e);else if(b(m,o)||b(v,o)||b(_,o))d[l]=D(o);else{if(!a.p)throw new Error(e+" missing "+o);a.p.load(a.n,A(r,!0),x(o),{}),d[l]=m[o]}s=n?n.apply(m[e],d):void 0,e&&(i&&i.exports!==h&&i.exports!==m[e]?m[e]=i.exports:s===h&&u||(m[e]=s))}else e&&(m[e]=n)},t=n=s=function(e,t,n,r,i){if("string"==typeof e)return g[e]?g[e](t):D(f(e,S(t)).f);if(!e.splice){if((y=e).deps&&s(y.deps,y.callback),!t)return;t.splice?(e=t,t=n,n=null):e=h}return t=t||function(){},"function"==typeof n&&(n=r,r=i),r?o(h,e,t,n):setTimeout(function(){o(h,e,t,n)},4),s},s.config=function(e){return s(e)},t._defined=m,(r=function(e,t,n){if("string"!=typeof e)throw new Error("See almond README: incorrect module build, no module name");t.splice||(n=t,t=[]),b(m,e)||b(v,e)||(v[e]=[e,t,n])}).amd={jQuery:!0},e.requirejs=t,e.require=n,e.define=r),e.define("almond",function(){}),e.define("jquery",[],function(){var e=u||$;return null==e&&console&&console.error&&console.error("Select2: An instance of jQuery or a jQuery-compatible library was not found. Make sure that you are including jQuery before Select2 on your web page."),e}),e.define("select2/utils",["jquery"],function(o){var i={};function u(e){var t=e.prototype,n=[];for(var r in t){"function"==typeof t[r]&&"constructor"!==r&&n.push(r)}return n}i.Extend=function(e,t){var n={}.hasOwnProperty;function r(){this.constructor=e}for(var i in t)n.call(t,i)&&(e[i]=t[i]);return r.prototype=t.prototype,e.prototype=new r,e.__super__=t.prototype,e},i.Decorate=function(r,i){var e=u(i),t=u(r);function o(){var e=Array.prototype.unshift,t=i.prototype.constructor.length,n=r.prototype.constructor;0<t&&(e.call(arguments,r.prototype.constructor),n=i.prototype.constructor),n.apply(this,arguments)}i.displayName=r.displayName,o.prototype=new function(){this.constructor=o};for(var n=0;n<t.length;n++){var s=t[n];o.prototype[s]=r.prototype[s]}function a(e){var t=function(){};e in o.prototype&&(t=o.prototype[e]);var n=i.prototype[e];return function(){return Array.prototype.unshift.call(arguments,t),n.apply(this,arguments)}}for(var l=0;l<e.length;l++){var c=e[l];o.prototype[c]=a(c)}return o};function e(){this.listeners={}}e.prototype.on=function(e,t){this.listeners=this.listeners||{},e in this.listeners?this.listeners[e].push(t):this.listeners[e]=[t]},e.prototype.trigger=function(e){var t=Array.prototype.slice,n=t.call(arguments,1);this.listeners=this.listeners||{},null==n&&(n=[]),0===n.length&&n.push({}),(n[0]._type=e)in this.listeners&&this.invoke(this.listeners[e],t.call(arguments,1)),"*"in this.listeners&&this.invoke(this.listeners["*"],arguments)},e.prototype.invoke=function(e,t){for(var n=0,r=e.length;n<r;n++)e[n].apply(this,t)},i.Observable=e,i.generateChars=function(e){for(var t="",n=0;n<e;n++){t+=Math.floor(36*Math.random()).toString(36)}return t},i.bind=function(e,t){return function(){e.apply(t,arguments)}},i._convertData=function(e){for(var t in e){var n=t.split("-"),r=e;if(1!==n.length){for(var i=0;i<n.length;i++){var o=n[i];(o=o.substring(0,1).toLowerCase()+o.substring(1))in r||(r[o]={}),i==n.length-1&&(r[o]=e[t]),r=r[o]}delete e[t]}}return e},i.hasScroll=function(e,t){var n=o(t),r=t.style.overflowX,i=t.style.overflowY;return(r!==i||"hidden"!==i&&"visible"!==i)&&("scroll"===r||"scroll"===i||(n.innerHeight()<t.scrollHeight||n.innerWidth()<t.scrollWidth))},i.escapeMarkup=function(e){var t={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return"string"!=typeof e?e:String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})},i.appendMany=function(e,t){if("1.7"===o.fn.jquery.substr(0,3)){var n=o();o.map(t,function(e){n=n.add(e)}),t=n}e.append(t)},i.__cache={};var n=0;return i.GetUniqueElementId=function(e){var t=e.getAttribute("data-select2-id");return null==t&&(e.id?(t=e.id,e.setAttribute("data-select2-id",t)):(e.setAttribute("data-select2-id",++n),t=n.toString())),t},i.StoreData=function(e,t,n){var r=i.GetUniqueElementId(e);i.__cache[r]||(i.__cache[r]={}),i.__cache[r][t]=n},i.GetData=function(e,t){var n=i.GetUniqueElementId(e);return t?i.__cache[n]&&null!=i.__cache[n][t]?i.__cache[n][t]:o(e).data(t):i.__cache[n]},i.RemoveData=function(e){var t=i.GetUniqueElementId(e);null!=i.__cache[t]&&delete i.__cache[t],e.removeAttribute("data-select2-id")},i}),e.define("select2/results",["jquery","./utils"],function(h,f){function r(e,t,n){this.$element=e,this.data=n,this.options=t,r.__super__.constructor.call(this)}return f.Extend(r,f.Observable),r.prototype.render=function(){var e=h('<ul class="select2-results__options" role="listbox"></ul>');return this.options.get("multiple")&&e.attr("aria-multiselectable","true"),this.$results=e},r.prototype.clear=function(){this.$results.empty()},r.prototype.displayMessage=function(e){var t=this.options.get("escapeMarkup");this.clear(),this.hideLoading();var n=h('<li role="alert" aria-live="assertive" class="select2-results__option"></li>'),r=this.options.get("translations").get(e.message);n.append(t(r(e.args))),n[0].className+=" select2-results__message",this.$results.append(n)},r.prototype.hideMessages=function(){this.$results.find(".select2-results__message").remove()},r.prototype.append=function(e){this.hideLoading();var t=[];if(null!=e.results&&0!==e.results.length){e.results=this.sort(e.results);for(var n=0;n<e.results.length;n++){var r=e.results[n],i=this.option(r);t.push(i)}this.$results.append(t)}else 0===this.$results.children().length&&this.trigger("results:message",{message:"noResults"})},r.prototype.position=function(e,t){t.find(".select2-results").append(e)},r.prototype.sort=function(e){return this.options.get("sorter")(e)},r.prototype.highlightFirstItem=function(){var e=this.$results.find(".select2-results__option[aria-selected]"),t=e.filter("[aria-selected=true]");0<t.length?t.first().trigger("mouseenter"):e.first().trigger("mouseenter"),this.ensureHighlightVisible()},r.prototype.setClasses=function(){var t=this;this.data.current(function(e){var r=h.map(e,function(e){return e.id.toString()});t.$results.find(".select2-results__option[aria-selected]").each(function(){var e=h(this),t=f.GetData(this,"data"),n=""+t.id;null!=t.element&&t.element.selected||null==t.element&&-1<h.inArray(n,r)?e.attr("aria-selected","true"):e.attr("aria-selected","false")})})},r.prototype.showLoading=function(e){this.hideLoading();var t={disabled:!0,loading:!0,text:this.options.get("translations").get("searching")(e)},n=this.option(t);n.className+=" loading-results",this.$results.prepend(n)},r.prototype.hideLoading=function(){this.$results.find(".loading-results").remove()},r.prototype.option=function(e){var t=document.createElement("li");t.className="select2-results__option";var n={role:"option","aria-selected":"false"},r=window.Element.prototype.matches||window.Element.prototype.msMatchesSelector||window.Element.prototype.webkitMatchesSelector;for(var i in(null!=e.element&&r.call(e.element,":disabled")||null==e.element&&e.disabled)&&(delete n["aria-selected"],n["aria-disabled"]="true"),null==e.id&&delete n["aria-selected"],null!=e._resultId&&(t.id=e._resultId),e.title&&(t.title=e.title),e.children&&(n.role="group",n["aria-label"]=e.text,delete n["aria-selected"]),n){var o=n[i];t.setAttribute(i,o)}if(e.children){var s=h(t),a=document.createElement("strong");a.className="select2-results__group";h(a);this.template(e,a);for(var l=[],c=0;c<e.children.length;c++){var u=e.children[c],d=this.option(u);l.push(d)}var p=h("<ul></ul>",{class:"select2-results__options select2-results__options--nested"});p.append(l),s.append(a),s.append(p)}else this.template(e,t);return f.StoreData(t,"data",e),t},r.prototype.bind=function(t,e){var l=this,n=t.id+"-results";this.$results.attr("id",n),t.on("results:all",function(e){l.clear(),l.append(e.data),t.isOpen()&&(l.setClasses(),l.highlightFirstItem())}),t.on("results:append",function(e){l.append(e.data),t.isOpen()&&l.setClasses()}),t.on("query",function(e){l.hideMessages(),l.showLoading(e)}),t.on("select",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("unselect",function(){t.isOpen()&&(l.setClasses(),l.options.get("scrollAfterSelect")&&l.highlightFirstItem())}),t.on("open",function(){l.$results.attr("aria-expanded","true"),l.$results.attr("aria-hidden","false"),l.setClasses(),l.ensureHighlightVisible()}),t.on("close",function(){l.$results.attr("aria-expanded","false"),l.$results.attr("aria-hidden","true"),l.$results.removeAttr("aria-activedescendant")}),t.on("results:toggle",function(){var e=l.getHighlightedResults();0!==e.length&&e.trigger("mouseup")}),t.on("results:select",function(){var e=l.getHighlightedResults();if(0!==e.length){var t=f.GetData(e[0],"data");"true"==e.attr("aria-selected")?l.trigger("close",{}):l.trigger("select",{data:t})}}),t.on("results:previous",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e);if(!(n<=0)){var r=n-1;0===e.length&&(r=0);var i=t.eq(r);i.trigger("mouseenter");var o=l.$results.offset().top,s=i.offset().top,a=l.$results.scrollTop()+(s-o);0===r?l.$results.scrollTop(0):s-o<0&&l.$results.scrollTop(a)}}),t.on("results:next",function(){var e=l.getHighlightedResults(),t=l.$results.find("[aria-selected]"),n=t.index(e)+1;if(!(n>=t.length)){var r=t.eq(n);r.trigger("mouseenter");var i=l.$results.offset().top+l.$results.outerHeight(!1),o=r.offset().top+r.outerHeight(!1),s=l.$results.scrollTop()+o-i;0===n?l.$results.scrollTop(0):i<o&&l.$results.scrollTop(s)}}),t.on("results:focus",function(e){e.element.addClass("select2-results__option--highlighted")}),t.on("results:message",function(e){l.displayMessage(e)}),h.fn.mousewheel&&this.$results.on("mousewheel",function(e){var t=l.$results.scrollTop(),n=l.$results.get(0).scrollHeight-t+e.deltaY,r=0<e.deltaY&&t-e.deltaY<=0,i=e.deltaY<0&&n<=l.$results.height();r?(l.$results.scrollTop(0),e.preventDefault(),e.stopPropagation()):i&&(l.$results.scrollTop(l.$results.get(0).scrollHeight-l.$results.height()),e.preventDefault(),e.stopPropagation())}),this.$results.on("mouseup",".select2-results__option[aria-selected]",function(e){var t=h(this),n=f.GetData(this,"data");"true"!==t.attr("aria-selected")?l.trigger("select",{originalEvent:e,data:n}):l.options.get("multiple")?l.trigger("unselect",{originalEvent:e,data:n}):l.trigger("close",{})}),this.$results.on("mouseenter",".select2-results__option[aria-selected]",function(e){var t=f.GetData(this,"data");l.getHighlightedResults().removeClass("select2-results__option--highlighted"),l.trigger("results:focus",{data:t,element:h(this)})})},r.prototype.getHighlightedResults=function(){return this.$results.find(".select2-results__option--highlighted")},r.prototype.destroy=function(){this.$results.remove()},r.prototype.ensureHighlightVisible=function(){var e=this.getHighlightedResults();if(0!==e.length){var t=this.$results.find("[aria-selected]").index(e),n=this.$results.offset().top,r=e.offset().top,i=this.$results.scrollTop()+(r-n),o=r-n;i-=2*e.outerHeight(!1),t<=2?this.$results.scrollTop(0):(o>this.$results.outerHeight()||o<0)&&this.$results.scrollTop(i)}},r.prototype.template=function(e,t){var n=this.options.get("templateResult"),r=this.options.get("escapeMarkup"),i=n(e,t);null==i?t.style.display="none":"string"==typeof i?t.innerHTML=r(i):h(t).append(i)},r}),e.define("select2/keys",[],function(){return{BACKSPACE:8,TAB:9,ENTER:13,SHIFT:16,CTRL:17,ALT:18,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,DELETE:46}}),e.define("select2/selection/base",["jquery","../utils","../keys"],function(n,r,i){function o(e,t){this.$element=e,this.options=t,o.__super__.constructor.call(this)}return r.Extend(o,r.Observable),o.prototype.render=function(){var e=n('<span class="select2-selection" role="combobox" aria-haspopup="true" aria-expanded="false"></span>');return this._tabindex=0,null!=r.GetData(this.$element[0],"old-tabindex")?this._tabindex=r.GetData(this.$element[0],"old-tabindex"):null!=this.$element.attr("tabindex")&&(this._tabindex=this.$element.attr("tabindex")),e.attr("title",this.$element.attr("title")),e.attr("tabindex",this._tabindex),e.attr("aria-disabled","false"),this.$selection=e},o.prototype.bind=function(e,t){var n=this,r=e.id+"-results";this.container=e,this.$selection.on("focus",function(e){n.trigger("focus",e)}),this.$selection.on("blur",function(e){n._handleBlur(e)}),this.$selection.on("keydown",function(e){n.trigger("keypress",e),e.which===i.SPACE&&e.preventDefault()}),e.on("results:focus",function(e){n.$selection.attr("aria-activedescendant",e.data._resultId)}),e.on("selection:update",function(e){n.update(e.data)}),e.on("open",function(){n.$selection.attr("aria-expanded","true"),n.$selection.attr("aria-owns",r),n._attachCloseHandler(e)}),e.on("close",function(){n.$selection.attr("aria-expanded","false"),n.$selection.removeAttr("aria-activedescendant"),n.$selection.removeAttr("aria-owns"),n.$selection.trigger("focus"),n._detachCloseHandler(e)}),e.on("enable",function(){n.$selection.attr("tabindex",n._tabindex),n.$selection.attr("aria-disabled","false")}),e.on("disable",function(){n.$selection.attr("tabindex","-1"),n.$selection.attr("aria-disabled","true")})},o.prototype._handleBlur=function(e){var t=this;window.setTimeout(function(){document.activeElement==t.$selection[0]||n.contains(t.$selection[0],document.activeElement)||t.trigger("blur",e)},1)},o.prototype._attachCloseHandler=function(e){n(document.body).on("mousedown.select2."+e.id,function(e){var t=n(e.target).closest(".select2");n(".select2.select2-container--open").each(function(){this!=t[0]&&r.GetData(this,"element").select2("close")})})},o.prototype._detachCloseHandler=function(e){n(document.body).off("mousedown.select2."+e.id)},o.prototype.position=function(e,t){t.find(".selection").append(e)},o.prototype.destroy=function(){this._detachCloseHandler(this.container)},o.prototype.update=function(e){throw new Error("The `update` method must be defined in child classes.")},o}),e.define("select2/selection/single",["jquery","./base","../utils","../keys"],function(e,t,n,r){function i(){i.__super__.constructor.apply(this,arguments)}return n.Extend(i,t),i.prototype.render=function(){var e=i.__super__.render.call(this);return e.addClass("select2-selection--single"),e.html('<span class="select2-selection__rendered"></span><span class="select2-selection__arrow" role="presentation"><b role="presentation"></b></span>'),e},i.prototype.bind=function(t,e){var n=this;i.__super__.bind.apply(this,arguments);var r=t.id+"-container";this.$selection.find(".select2-selection__rendered").attr("id",r).attr("role","textbox").attr("aria-readonly","true"),this.$selection.attr("aria-labelledby",r),this.$selection.on("mousedown",function(e){1===e.which&&n.trigger("toggle",{originalEvent:e})}),this.$selection.on("focus",function(e){}),this.$selection.on("blur",function(e){}),t.on("focus",function(e){t.isOpen()||n.$selection.trigger("focus")})},i.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},i.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},i.prototype.selectionContainer=function(){return e("<span></span>")},i.prototype.update=function(e){if(0!==e.length){var t=e[0],n=this.$selection.find(".select2-selection__rendered"),r=this.display(t,n);n.empty().append(r);var i=t.title||t.text;i?n.attr("title",i):n.removeAttr("title")}else this.clear()},i}),e.define("select2/selection/multiple",["jquery","./base","../utils"],function(i,e,l){function n(e,t){n.__super__.constructor.apply(this,arguments)}return l.Extend(n,e),n.prototype.render=function(){var e=n.__super__.render.call(this);return e.addClass("select2-selection--multiple"),e.html('<ul class="select2-selection__rendered"></ul>'),e},n.prototype.bind=function(e,t){var r=this;n.__super__.bind.apply(this,arguments),this.$selection.on("click",function(e){r.trigger("toggle",{originalEvent:e})}),this.$selection.on("click",".select2-selection__choice__remove",function(e){if(!r.options.get("disabled")){var t=i(this).parent(),n=l.GetData(t[0],"data");r.trigger("unselect",{originalEvent:e,data:n})}})},n.prototype.clear=function(){var e=this.$selection.find(".select2-selection__rendered");e.empty(),e.removeAttr("title")},n.prototype.display=function(e,t){var n=this.options.get("templateSelection");return this.options.get("escapeMarkup")(n(e,t))},n.prototype.selectionContainer=function(){return i('<li class="select2-selection__choice"><span class="select2-selection__choice__remove" role="presentation">&times;</span></li>')},n.prototype.update=function(e){if(this.clear(),0!==e.length){for(var t=[],n=0;n<e.length;n++){var r=e[n],i=this.selectionContainer(),o=this.display(r,i);i.append(o);var s=r.title||r.text;s&&i.attr("title",s),l.StoreData(i[0],"data",r),t.push(i)}var a=this.$selection.find(".select2-selection__rendered");l.appendMany(a,t)}},n}),e.define("select2/selection/placeholder",["../utils"],function(e){function t(e,t,n){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n)}return t.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},t.prototype.createPlaceholder=function(e,t){var n=this.selectionContainer();return n.html(this.display(t)),n.addClass("select2-selection__placeholder").removeClass("select2-selection__choice"),n},t.prototype.update=function(e,t){var n=1==t.length&&t[0].id!=this.placeholder.id;if(1<t.length||n)return e.call(this,t);this.clear();var r=this.createPlaceholder(this.placeholder);this.$selection.find(".select2-selection__rendered").append(r)},t}),e.define("select2/selection/allowClear",["jquery","../keys","../utils"],function(i,r,a){function e(){}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),null==this.placeholder&&this.options.get("debug")&&window.console&&console.error&&console.error("Select2: The `allowClear` option should be used in combination with the `placeholder` option."),this.$selection.on("mousedown",".select2-selection__clear",function(e){r._handleClear(e)}),t.on("keypress",function(e){r._handleKeyboardClear(e,t)})},e.prototype._handleClear=function(e,t){if(!this.options.get("disabled")){var n=this.$selection.find(".select2-selection__clear");if(0!==n.length){t.stopPropagation();var r=a.GetData(n[0],"data"),i=this.$element.val();this.$element.val(this.placeholder.id);var o={data:r};if(this.trigger("clear",o),o.prevented)this.$element.val(i);else{for(var s=0;s<r.length;s++)if(o={data:r[s]},this.trigger("unselect",o),o.prevented)return void this.$element.val(i);this.$element.trigger("change"),this.trigger("toggle",{})}}}},e.prototype._handleKeyboardClear=function(e,t,n){n.isOpen()||t.which!=r.DELETE&&t.which!=r.BACKSPACE||this._handleClear(t)},e.prototype.update=function(e,t){if(e.call(this,t),!(0<this.$selection.find(".select2-selection__placeholder").length||0===t.length)){var n=this.options.get("translations").get("removeAllItems"),r=i('<span class="select2-selection__clear" title="'+n()+'">&times;</span>');a.StoreData(r[0],"data",t),this.$selection.find(".select2-selection__rendered").prepend(r)}},e}),e.define("select2/selection/search",["jquery","../utils","../keys"],function(r,a,l){function e(e,t,n){e.call(this,t,n)}return e.prototype.render=function(e){var t=r('<li class="select2-search select2-search--inline"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="searchbox" aria-autocomplete="list" /></li>');this.$searchContainer=t,this.$search=t.find("input");var n=e.call(this);return this._transferTabIndex(),n},e.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),t.on("open",function(){r.$search.attr("aria-controls",i),r.$search.trigger("focus")}),t.on("close",function(){r.$search.val(""),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.trigger("focus")}),t.on("enable",function(){r.$search.prop("disabled",!1),r._transferTabIndex()}),t.on("disable",function(){r.$search.prop("disabled",!0)}),t.on("focus",function(e){r.$search.trigger("focus")}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")}),this.$selection.on("focusin",".select2-search--inline",function(e){r.trigger("focus",e)}),this.$selection.on("focusout",".select2-search--inline",function(e){r._handleBlur(e)}),this.$selection.on("keydown",".select2-search--inline",function(e){if(e.stopPropagation(),r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented(),e.which===l.BACKSPACE&&""===r.$search.val()){var t=r.$searchContainer.prev(".select2-selection__choice");if(0<t.length){var n=a.GetData(t[0],"data");r.searchRemoveChoice(n),e.preventDefault()}}}),this.$selection.on("click",".select2-search--inline",function(e){r.$search.val()&&e.stopPropagation()});var o=document.documentMode,s=o&&o<=11;this.$selection.on("input.searchcheck",".select2-search--inline",function(e){s?r.$selection.off("input.search input.searchcheck"):r.$selection.off("keyup.search")}),this.$selection.on("keyup.search input.search",".select2-search--inline",function(e){if(s&&"input"===e.type)r.$selection.off("input.search input.searchcheck");else{var t=e.which;t!=l.SHIFT&&t!=l.CTRL&&t!=l.ALT&&t!=l.TAB&&r.handleSearch(e)}})},e.prototype._transferTabIndex=function(e){this.$search.attr("tabindex",this.$selection.attr("tabindex")),this.$selection.attr("tabindex","-1")},e.prototype.createPlaceholder=function(e,t){this.$search.attr("placeholder",t.text)},e.prototype.update=function(e,t){var n=this.$search[0]==document.activeElement;this.$search.attr("placeholder",""),e.call(this,t),this.$selection.find(".select2-selection__rendered").append(this.$searchContainer),this.resizeSearch(),n&&this.$search.trigger("focus")},e.prototype.handleSearch=function(){if(this.resizeSearch(),!this._keyUpPrevented){var e=this.$search.val();this.trigger("query",{term:e})}this._keyUpPrevented=!1},e.prototype.searchRemoveChoice=function(e,t){this.trigger("unselect",{data:t}),this.$search.val(t.text),this.handleSearch()},e.prototype.resizeSearch=function(){this.$search.css("width","25px");var e="";""!==this.$search.attr("placeholder")?e=this.$selection.find(".select2-selection__rendered").width():e=.75*(this.$search.val().length+1)+"em";this.$search.css("width",e)},e}),e.define("select2/selection/eventRelay",["jquery"],function(s){function e(){}return e.prototype.bind=function(e,t,n){var r=this,i=["open","opening","close","closing","select","selecting","unselect","unselecting","clear","clearing"],o=["opening","closing","selecting","unselecting","clearing"];e.call(this,t,n),t.on("*",function(e,t){if(-1!==s.inArray(e,i)){t=t||{};var n=s.Event("select2:"+e,{params:t});r.$element.trigger(n),-1!==s.inArray(e,o)&&(t.prevented=n.isDefaultPrevented())}})},e}),e.define("select2/translation",["jquery","require"],function(t,n){function r(e){this.dict=e||{}}return r.prototype.all=function(){return this.dict},r.prototype.get=function(e){return this.dict[e]},r.prototype.extend=function(e){this.dict=t.extend({},e.all(),this.dict)},r._cache={},r.loadPath=function(e){if(!(e in r._cache)){var t=n(e);r._cache[e]=t}return new r(r._cache[e])},r}),e.define("select2/diacritics",[],function(){return{"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Œ":"OE","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","œ":"oe","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ώ":"ω","ς":"σ","’":"'"}}),e.define("select2/data/base",["../utils"],function(r){function n(e,t){n.__super__.constructor.call(this)}return r.Extend(n,r.Observable),n.prototype.current=function(e){throw new Error("The `current` method must be defined in child classes.")},n.prototype.query=function(e,t){throw new Error("The `query` method must be defined in child classes.")},n.prototype.bind=function(e,t){},n.prototype.destroy=function(){},n.prototype.generateResultId=function(e,t){var n=e.id+"-result-";return n+=r.generateChars(4),null!=t.id?n+="-"+t.id.toString():n+="-"+r.generateChars(4),n},n}),e.define("select2/data/select",["./base","../utils","jquery"],function(e,a,l){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return a.Extend(n,e),n.prototype.current=function(e){var n=[],r=this;this.$element.find(":selected").each(function(){var e=l(this),t=r.item(e);n.push(t)}),e(n)},n.prototype.select=function(i){var o=this;if(i.selected=!0,l(i.element).is("option"))return i.element.selected=!0,void this.$element.trigger("change");if(this.$element.prop("multiple"))this.current(function(e){var t=[];(i=[i]).push.apply(i,e);for(var n=0;n<i.length;n++){var r=i[n].id;-1===l.inArray(r,t)&&t.push(r)}o.$element.val(t),o.$element.trigger("change")});else{var e=i.id;this.$element.val(e),this.$element.trigger("change")}},n.prototype.unselect=function(i){var o=this;if(this.$element.prop("multiple")){if(i.selected=!1,l(i.element).is("option"))return i.element.selected=!1,void this.$element.trigger("change");this.current(function(e){for(var t=[],n=0;n<e.length;n++){var r=e[n].id;r!==i.id&&-1===l.inArray(r,t)&&t.push(r)}o.$element.val(t),o.$element.trigger("change")})}},n.prototype.bind=function(e,t){var n=this;(this.container=e).on("select",function(e){n.select(e.data)}),e.on("unselect",function(e){n.unselect(e.data)})},n.prototype.destroy=function(){this.$element.find("*").each(function(){a.RemoveData(this)})},n.prototype.query=function(r,e){var i=[],o=this;this.$element.children().each(function(){var e=l(this);if(e.is("option")||e.is("optgroup")){var t=o.item(e),n=o.matches(r,t);null!==n&&i.push(n)}}),e({results:i})},n.prototype.addOptions=function(e){a.appendMany(this.$element,e)},n.prototype.option=function(e){var t;e.children?(t=document.createElement("optgroup")).label=e.text:void 0!==(t=document.createElement("option")).textContent?t.textContent=e.text:t.innerText=e.text,void 0!==e.id&&(t.value=e.id),e.disabled&&(t.disabled=!0),e.selected&&(t.selected=!0),e.title&&(t.title=e.title);var n=l(t),r=this._normalizeItem(e);return r.element=t,a.StoreData(t,"data",r),n},n.prototype.item=function(e){var t={};if(null!=(t=a.GetData(e[0],"data")))return t;if(e.is("option"))t={id:e.val(),text:e.text(),disabled:e.prop("disabled"),selected:e.prop("selected"),title:e.prop("title")};else if(e.is("optgroup")){t={text:e.prop("label"),children:[],title:e.prop("title")};for(var n=e.children("option"),r=[],i=0;i<n.length;i++){var o=l(n[i]),s=this.item(o);r.push(s)}t.children=r}return(t=this._normalizeItem(t)).element=e[0],a.StoreData(e[0],"data",t),t},n.prototype._normalizeItem=function(e){e!==Object(e)&&(e={id:e,text:e});return null!=(e=l.extend({},{text:""},e)).id&&(e.id=e.id.toString()),null!=e.text&&(e.text=e.text.toString()),null==e._resultId&&e.id&&null!=this.container&&(e._resultId=this.generateResultId(this.container,e)),l.extend({},{selected:!1,disabled:!1},e)},n.prototype.matches=function(e,t){return this.options.get("matcher")(e,t)},n}),e.define("select2/data/array",["./select","../utils","jquery"],function(e,f,g){function r(e,t){this._dataToConvert=t.get("data")||[],r.__super__.constructor.call(this,e,t)}return f.Extend(r,e),r.prototype.bind=function(e,t){r.__super__.bind.call(this,e,t),this.addOptions(this.convertToOptions(this._dataToConvert))},r.prototype.select=function(n){var e=this.$element.find("option").filter(function(e,t){return t.value==n.id.toString()});0===e.length&&(e=this.option(n),this.addOptions(e)),r.__super__.select.call(this,n)},r.prototype.convertToOptions=function(e){var t=this,n=this.$element.find("option"),r=n.map(function(){return t.item(g(this)).id}).get(),i=[];function o(e){return function(){return g(this).val()==e.id}}for(var s=0;s<e.length;s++){var a=this._normalizeItem(e[s]);if(0<=g.inArray(a.id,r)){var l=n.filter(o(a)),c=this.item(l),u=g.extend(!0,{},a,c),d=this.option(u);l.replaceWith(d)}else{var p=this.option(a);if(a.children){var h=this.convertToOptions(a.children);f.appendMany(p,h)}i.push(p)}}return i},r}),e.define("select2/data/ajax",["./array","../utils","jquery"],function(e,t,o){function n(e,t){this.ajaxOptions=this._applyDefaults(t.get("ajax")),null!=this.ajaxOptions.processResults&&(this.processResults=this.ajaxOptions.processResults),n.__super__.constructor.call(this,e,t)}return t.Extend(n,e),n.prototype._applyDefaults=function(e){var t={data:function(e){return o.extend({},e,{q:e.term})},transport:function(e,t,n){var r=o.ajax(e);return r.then(t),r.fail(n),r}};return o.extend({},t,e,!0)},n.prototype.processResults=function(e){return e},n.prototype.query=function(n,r){var i=this;null!=this._request&&(o.isFunction(this._request.abort)&&this._request.abort(),this._request=null);var t=o.extend({type:"GET"},this.ajaxOptions);function e(){var e=t.transport(t,function(e){var t=i.processResults(e,n);i.options.get("debug")&&window.console&&console.error&&(t&&t.results&&o.isArray(t.results)||console.error("Select2: The AJAX results did not return an array in the `results` key of the response.")),r(t)},function(){"status"in e&&(0===e.status||"0"===e.status)||i.trigger("results:message",{message:"errorLoading"})});i._request=e}"function"==typeof t.url&&(t.url=t.url.call(this.$element,n)),"function"==typeof t.data&&(t.data=t.data.call(this.$element,n)),this.ajaxOptions.delay&&null!=n.term?(this._queryTimeout&&window.clearTimeout(this._queryTimeout),this._queryTimeout=window.setTimeout(e,this.ajaxOptions.delay)):e()},n}),e.define("select2/data/tags",["jquery"],function(u){function e(e,t,n){var r=n.get("tags"),i=n.get("createTag");void 0!==i&&(this.createTag=i);var o=n.get("insertTag");if(void 0!==o&&(this.insertTag=o),e.call(this,t,n),u.isArray(r))for(var s=0;s<r.length;s++){var a=r[s],l=this._normalizeItem(a),c=this.option(l);this.$element.append(c)}}return e.prototype.query=function(e,c,u){var d=this;this._removeOldTags(),null!=c.term&&null==c.page?e.call(this,c,function e(t,n){for(var r=t.results,i=0;i<r.length;i++){var o=r[i],s=null!=o.children&&!e({results:o.children},!0);if((o.text||"").toUpperCase()===(c.term||"").toUpperCase()||s)return!n&&(t.data=r,void u(t))}if(n)return!0;var a=d.createTag(c);if(null!=a){var l=d.option(a);l.attr("data-select2-tag",!0),d.addOptions([l]),d.insertTag(r,a)}t.results=r,u(t)}):e.call(this,c,u)},e.prototype.createTag=function(e,t){var n=u.trim(t.term);return""===n?null:{id:n,text:n}},e.prototype.insertTag=function(e,t,n){t.unshift(n)},e.prototype._removeOldTags=function(e){this.$element.find("option[data-select2-tag]").each(function(){this.selected||u(this).remove()})},e}),e.define("select2/data/tokenizer",["jquery"],function(d){function e(e,t,n){var r=n.get("tokenizer");void 0!==r&&(this.tokenizer=r),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){e.call(this,t,n),this.$search=t.dropdown.$search||t.selection.$search||n.find(".select2-search__field")},e.prototype.query=function(e,t,n){var r=this;t.term=t.term||"";var i=this.tokenizer(t,this.options,function(e){var t=r._normalizeItem(e);if(!r.$element.find("option").filter(function(){return d(this).val()===t.id}).length){var n=r.option(t);n.attr("data-select2-tag",!0),r._removeOldTags(),r.addOptions([n])}!function(e){r.trigger("select",{data:e})}(t)});i.term!==t.term&&(this.$search.length&&(this.$search.val(i.term),this.$search.trigger("focus")),t.term=i.term),e.call(this,t,n)},e.prototype.tokenizer=function(e,t,n,r){for(var i=n.get("tokenSeparators")||[],o=t.term,s=0,a=this.createTag||function(e){return{id:e.term,text:e.term}};s<o.length;){var l=o[s];if(-1!==d.inArray(l,i)){var c=o.substr(0,s),u=a(d.extend({},t,{term:c}));null!=u?(r(u),o=o.substr(s+1)||"",s=0):s++}else s++}return{term:o}},e}),e.define("select2/data/minimumInputLength",[],function(){function e(e,t,n){this.minimumInputLength=n.get("minimumInputLength"),e.call(this,t,n)}return e.prototype.query=function(e,t,n){t.term=t.term||"",t.term.length<this.minimumInputLength?this.trigger("results:message",{message:"inputTooShort",args:{minimum:this.minimumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumInputLength",[],function(){function e(e,t,n){this.maximumInputLength=n.get("maximumInputLength"),e.call(this,t,n)}return e.prototype.query=function(e,t,n){t.term=t.term||"",0<this.maximumInputLength&&t.term.length>this.maximumInputLength?this.trigger("results:message",{message:"inputTooLong",args:{maximum:this.maximumInputLength,input:t.term,params:t}}):e.call(this,t,n)},e}),e.define("select2/data/maximumSelectionLength",[],function(){function e(e,t,n){this.maximumSelectionLength=n.get("maximumSelectionLength"),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("select",function(){r._checkIfMaximumSelected()})},e.prototype.query=function(e,t,n){var r=this;this._checkIfMaximumSelected(function(){e.call(r,t,n)})},e.prototype._checkIfMaximumSelected=function(e,n){var r=this;this.current(function(e){var t=null!=e?e.length:0;0<r.maximumSelectionLength&&t>=r.maximumSelectionLength?r.trigger("results:message",{message:"maximumSelected",args:{maximum:r.maximumSelectionLength}}):n&&n()})},e}),e.define("select2/dropdown",["jquery","./utils"],function(t,e){function n(e,t){this.$element=e,this.options=t,n.__super__.constructor.call(this)}return e.Extend(n,e.Observable),n.prototype.render=function(){var e=t('<span class="select2-dropdown"><span class="select2-results"></span></span>');return e.attr("dir",this.options.get("dir")),this.$dropdown=e},n.prototype.bind=function(){},n.prototype.position=function(e,t){},n.prototype.destroy=function(){this.$dropdown.remove()},n}),e.define("select2/dropdown/search",["jquery","../utils"],function(o,e){function t(){}return t.prototype.render=function(e){var t=e.call(this),n=o('<span class="select2-search select2-search--dropdown"><input class="select2-search__field" type="search" tabindex="-1" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="searchbox" aria-autocomplete="list" /></span>');return this.$searchContainer=n,this.$search=n.find("input"),t.prepend(n),t},t.prototype.bind=function(e,t,n){var r=this,i=t.id+"-results";e.call(this,t,n),this.$search.on("keydown",function(e){r.trigger("keypress",e),r._keyUpPrevented=e.isDefaultPrevented()}),this.$search.on("input",function(e){o(this).off("keyup")}),this.$search.on("keyup input",function(e){r.handleSearch(e)}),t.on("open",function(){r.$search.attr("tabindex",0),r.$search.attr("aria-controls",i),r.$search.trigger("focus"),window.setTimeout(function(){r.$search.trigger("focus")},0)}),t.on("close",function(){r.$search.attr("tabindex",-1),r.$search.removeAttr("aria-controls"),r.$search.removeAttr("aria-activedescendant"),r.$search.val(""),r.$search.trigger("blur")}),t.on("focus",function(){t.isOpen()||r.$search.trigger("focus")}),t.on("results:all",function(e){null!=e.query.term&&""!==e.query.term||(r.showSearch(e)?r.$searchContainer.removeClass("select2-search--hide"):r.$searchContainer.addClass("select2-search--hide"))}),t.on("results:focus",function(e){e.data._resultId?r.$search.attr("aria-activedescendant",e.data._resultId):r.$search.removeAttr("aria-activedescendant")})},t.prototype.handleSearch=function(e){if(!this._keyUpPrevented){var t=this.$search.val();this.trigger("query",{term:t})}this._keyUpPrevented=!1},t.prototype.showSearch=function(e,t){return!0},t}),e.define("select2/dropdown/hidePlaceholder",[],function(){function e(e,t,n,r){this.placeholder=this.normalizePlaceholder(n.get("placeholder")),e.call(this,t,n,r)}return e.prototype.append=function(e,t){t.results=this.removePlaceholder(t.results),e.call(this,t)},e.prototype.normalizePlaceholder=function(e,t){return"string"==typeof t&&(t={id:"",text:t}),t},e.prototype.removePlaceholder=function(e,t){for(var n=t.slice(0),r=t.length-1;0<=r;r--){var i=t[r];this.placeholder.id===i.id&&n.splice(r,1)}return n},e}),e.define("select2/dropdown/infiniteScroll",["jquery"],function(n){function e(e,t,n,r){this.lastParams={},e.call(this,t,n,r),this.$loadingMore=this.createLoadingMore(),this.loading=!1}return e.prototype.append=function(e,t){this.$loadingMore.remove(),this.loading=!1,e.call(this,t),this.showLoadingMore(t)&&(this.$results.append(this.$loadingMore),this.loadMoreIfNeeded())},e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("query",function(e){r.lastParams=e,r.loading=!0}),t.on("query:append",function(e){r.lastParams=e,r.loading=!0}),this.$results.on("scroll",this.loadMoreIfNeeded.bind(this))},e.prototype.loadMoreIfNeeded=function(){var e=n.contains(document.documentElement,this.$loadingMore[0]);if(!this.loading&&e){var t=this.$results.offset().top+this.$results.outerHeight(!1);this.$loadingMore.offset().top+this.$loadingMore.outerHeight(!1)<=t+50&&this.loadMore()}},e.prototype.loadMore=function(){this.loading=!0;var e=n.extend({},{page:1},this.lastParams);e.page++,this.trigger("query:append",e)},e.prototype.showLoadingMore=function(e,t){return t.pagination&&t.pagination.more},e.prototype.createLoadingMore=function(){var e=n('<li class="select2-results__option select2-results__option--load-more"role="option" aria-disabled="true"></li>'),t=this.options.get("translations").get("loadingMore");return e.html(t(this.lastParams)),e},e}),e.define("select2/dropdown/attachBody",["jquery","../utils"],function(f,a){function e(e,t,n){this.$dropdownParent=f(n.get("dropdownParent")||document.body),e.call(this,t,n)}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("open",function(){r._showDropdown(),r._attachPositioningHandler(t),r._bindContainerResultHandlers(t)}),t.on("close",function(){r._hideDropdown(),r._detachPositioningHandler(t)}),this.$dropdownContainer.on("mousedown",function(e){e.stopPropagation()})},e.prototype.destroy=function(e){e.call(this),this.$dropdownContainer.remove()},e.prototype.position=function(e,t,n){t.attr("class",n.attr("class")),t.removeClass("select2"),t.addClass("select2-container--open"),t.css({position:"absolute",top:-999999}),this.$container=n},e.prototype.render=function(e){var t=f("<span></span>"),n=e.call(this);return t.append(n),this.$dropdownContainer=t},e.prototype._hideDropdown=function(e){this.$dropdownContainer.detach()},e.prototype._bindContainerResultHandlers=function(e,t){if(!this._containerResultsHandlersBound){var n=this;t.on("results:all",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:append",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("results:message",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("select",function(){n._positionDropdown(),n._resizeDropdown()}),t.on("unselect",function(){n._positionDropdown(),n._resizeDropdown()}),this._containerResultsHandlersBound=!0}},e.prototype._attachPositioningHandler=function(e,t){var n=this,r="scroll.select2."+t.id,i="resize.select2."+t.id,o="orientationchange.select2."+t.id,s=this.$container.parents().filter(a.hasScroll);s.each(function(){a.StoreData(this,"select2-scroll-position",{x:f(this).scrollLeft(),y:f(this).scrollTop()})}),s.on(r,function(e){var t=a.GetData(this,"select2-scroll-position");f(this).scrollTop(t.y)}),f(window).on(r+" "+i+" "+o,function(e){n._positionDropdown(),n._resizeDropdown()})},e.prototype._detachPositioningHandler=function(e,t){var n="scroll.select2."+t.id,r="resize.select2."+t.id,i="orientationchange.select2."+t.id;this.$container.parents().filter(a.hasScroll).off(n),f(window).off(n+" "+r+" "+i)},e.prototype._positionDropdown=function(){var e=f(window),t=this.$dropdown.hasClass("select2-dropdown--above"),n=this.$dropdown.hasClass("select2-dropdown--below"),r=null,i=this.$container.offset();i.bottom=i.top+this.$container.outerHeight(!1);var o={height:this.$container.outerHeight(!1)};o.top=i.top,o.bottom=i.top+o.height;var s=this.$dropdown.outerHeight(!1),a=e.scrollTop(),l=e.scrollTop()+e.height(),c=a<i.top-s,u=l>i.bottom+s,d={left:i.left,top:o.bottom},p=this.$dropdownParent;"static"===p.css("position")&&(p=p.offsetParent());var h={top:0,left:0};(f.contains(document.body,p[0])||p[0].isConnected)&&(h=p.offset()),d.top-=h.top,d.left-=h.left,t||n||(r="below"),u||!c||t?!c&&u&&t&&(r="below"):r="above",("above"==r||t&&"below"!==r)&&(d.top=o.top-h.top-s),null!=r&&(this.$dropdown.removeClass("select2-dropdown--below select2-dropdown--above").addClass("select2-dropdown--"+r),this.$container.removeClass("select2-container--below select2-container--above").addClass("select2-container--"+r)),this.$dropdownContainer.css(d)},e.prototype._resizeDropdown=function(){var e={width:this.$container.outerWidth(!1)+"px"};this.options.get("dropdownAutoWidth")&&(e.minWidth=e.width,e.position="relative",e.width="auto"),this.$dropdown.css(e)},e.prototype._showDropdown=function(e){this.$dropdownContainer.appendTo(this.$dropdownParent),this._positionDropdown(),this._resizeDropdown()},e}),e.define("select2/dropdown/minimumResultsForSearch",[],function(){function e(e,t,n,r){this.minimumResultsForSearch=n.get("minimumResultsForSearch"),this.minimumResultsForSearch<0&&(this.minimumResultsForSearch=1/0),e.call(this,t,n,r)}return e.prototype.showSearch=function(e,t){return!(function e(t){for(var n=0,r=0;r<t.length;r++){var i=t[r];i.children?n+=e(i.children):n++}return n}(t.data.results)<this.minimumResultsForSearch)&&e.call(this,t)},e}),e.define("select2/dropdown/selectOnClose",["../utils"],function(o){function e(){}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("close",function(e){r._handleSelectOnClose(e)})},e.prototype._handleSelectOnClose=function(e,t){if(t&&null!=t.originalSelect2Event){var n=t.originalSelect2Event;if("select"===n._type||"unselect"===n._type)return}var r=this.getHighlightedResults();if(!(r.length<1)){var i=o.GetData(r[0],"data");null!=i.element&&i.element.selected||null==i.element&&i.selected||this.trigger("select",{data:i})}},e}),e.define("select2/dropdown/closeOnSelect",[],function(){function e(){}return e.prototype.bind=function(e,t,n){var r=this;e.call(this,t,n),t.on("select",function(e){r._selectTriggered(e)}),t.on("unselect",function(e){r._selectTriggered(e)})},e.prototype._selectTriggered=function(e,t){var n=t.originalEvent;n&&(n.ctrlKey||n.metaKey)||this.trigger("close",{originalEvent:n,originalSelect2Event:t})},e}),e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"Sonuçlar yüklenemedi."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Lütfen "+t+" karakterini kaldırın";return 1!=t&&(n+="s"),n},inputTooShort:function(e){return"Lütfen "+(e.minimum-e.input.length)+" veya daha fazla karakter girin"},loadingMore:function(){return"Daha fazla sonuç yükleniyor…"},maximumSelected:function(e){var t="En fazla "+e.maximum+" tane seçebilirsiniz";return 1!=e.maximum&&(t+="s"),t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tümünü kaldır"}}}),e.define("select2/defaults",["jquery","require","./results","./selection/single","./selection/multiple","./selection/placeholder","./selection/allowClear","./selection/search","./selection/eventRelay","./utils","./translation","./diacritics","./data/select","./data/array","./data/ajax","./data/tags","./data/tokenizer","./data/minimumInputLength","./data/maximumInputLength","./data/maximumSelectionLength","./dropdown","./dropdown/search","./dropdown/hidePlaceholder","./dropdown/infiniteScroll","./dropdown/attachBody","./dropdown/minimumResultsForSearch","./dropdown/selectOnClose","./dropdown/closeOnSelect","./i18n/en"],function(c,u,d,p,h,f,g,m,v,y,s,t,_,$,w,b,A,x,D,S,E,C,O,T,q,L,I,j,e){function n(){this.reset()}return n.prototype.apply=function(e){if(null==(e=c.extend(!0,{},this.defaults,e)).dataAdapter){if(null!=e.ajax?e.dataAdapter=w:null!=e.data?e.dataAdapter=$:e.dataAdapter=_,0<e.minimumInputLength&&(e.dataAdapter=y.Decorate(e.dataAdapter,x)),0<e.maximumInputLength&&(e.dataAdapter=y.Decorate(e.dataAdapter,D)),0<e.maximumSelectionLength&&(e.dataAdapter=y.Decorate(e.dataAdapter,S)),e.tags&&(e.dataAdapter=y.Decorate(e.dataAdapter,b)),null==e.tokenSeparators&&null==e.tokenizer||(e.dataAdapter=y.Decorate(e.dataAdapter,A)),null!=e.query){var t=u(e.amdBase+"compat/query");e.dataAdapter=y.Decorate(e.dataAdapter,t)}if(null!=e.initSelection){var n=u(e.amdBase+"compat/initSelection");e.dataAdapter=y.Decorate(e.dataAdapter,n)}}if(null==e.resultsAdapter&&(e.resultsAdapter=d,null!=e.ajax&&(e.resultsAdapter=y.Decorate(e.resultsAdapter,T)),null!=e.placeholder&&(e.resultsAdapter=y.Decorate(e.resultsAdapter,O)),e.selectOnClose&&(e.resultsAdapter=y.Decorate(e.resultsAdapter,I))),null==e.dropdownAdapter){if(e.multiple)e.dropdownAdapter=E;else{var r=y.Decorate(E,C);e.dropdownAdapter=r}if(0!==e.minimumResultsForSearch&&(e.dropdownAdapter=y.Decorate(e.dropdownAdapter,L)),e.closeOnSelect&&(e.dropdownAdapter=y.Decorate(e.dropdownAdapter,j)),null!=e.dropdownCssClass||null!=e.dropdownCss||null!=e.adaptDropdownCssClass){var i=u(e.amdBase+"compat/dropdownCss");e.dropdownAdapter=y.Decorate(e.dropdownAdapter,i)}e.dropdownAdapter=y.Decorate(e.dropdownAdapter,q)}if(null==e.selectionAdapter){if(e.multiple?e.selectionAdapter=h:e.selectionAdapter=p,null!=e.placeholder&&(e.selectionAdapter=y.Decorate(e.selectionAdapter,f)),e.allowClear&&(e.selectionAdapter=y.Decorate(e.selectionAdapter,g)),e.multiple&&(e.selectionAdapter=y.Decorate(e.selectionAdapter,m)),null!=e.containerCssClass||null!=e.containerCss||null!=e.adaptContainerCssClass){var o=u(e.amdBase+"compat/containerCss");e.selectionAdapter=y.Decorate(e.selectionAdapter,o)}e.selectionAdapter=y.Decorate(e.selectionAdapter,v)}e.language=this._resolveLanguage(e.language),e.language.push("en");for(var s=[],a=0;a<e.language.length;a++){var l=e.language[a];-1===s.indexOf(l)&&s.push(l)}return e.language=s,e.translations=this._processTranslations(e.language,e.debug),e},n.prototype.reset=function(){function a(e){return e.replace(/[^\u0000-\u007E]/g,function(e){return t[e]||e})}this.defaults={amdBase:"./",amdLanguageBase:"./i18n/",closeOnSelect:!0,debug:!1,dropdownAutoWidth:!1,escapeMarkup:y.escapeMarkup,language:{},matcher:function e(t,n){if(""===c.trim(t.term))return n;if(n.children&&0<n.children.length){for(var r=c.extend(!0,{},n),i=n.children.length-1;0<=i;i--)null==e(t,n.children[i])&&r.children.splice(i,1);return 0<r.children.length?r:e(t,r)}var o=a(n.text).toUpperCase(),s=a(t.term).toUpperCase();return-1<o.indexOf(s)?n:null},minimumInputLength:0,maximumInputLength:0,maximumSelectionLength:0,minimumResultsForSearch:0,selectOnClose:!1,scrollAfterSelect:!1,sorter:function(e){return e},templateResult:function(e){return e.text},templateSelection:function(e){return e.text},theme:"default",width:"resolve"}},n.prototype.applyFromElement=function(e,t){var n=e.language,r=this.defaults.language,i=t.prop("lang"),o=t.closest("[lang]").prop("lang"),s=Array.prototype.concat.call(this._resolveLanguage(i),this._resolveLanguage(n),this._resolveLanguage(r),this._resolveLanguage(o));return e.language=s,e},n.prototype._resolveLanguage=function(e){if(!e)return[];if(c.isEmptyObject(e))return[];if(c.isPlainObject(e))return[e];var t;t=c.isArray(e)?e:[e];for(var n=[],r=0;r<t.length;r++)if(n.push(t[r]),"string"==typeof t[r]&&0<t[r].indexOf("-")){var i=t[r].split("-")[0];n.push(i)}return n},n.prototype._processTranslations=function(e,t){for(var n=new s,r=0;r<e.length;r++){var i=new s,o=e[r];if("string"==typeof o)try{i=s.loadPath(o)}catch(e){try{o=this.defaults.amdLanguageBase+o,i=s.loadPath(o)}catch(e){t&&window.console&&console.warn&&console.warn('Select2: The language file for "'+o+'" could not be automatically loaded. A fallback will be used instead.')}}else i=c.isPlainObject(o)?new s(o):o;n.extend(i)}return n},n.prototype.set=function(e,t){var n={};n[c.camelCase(e)]=t;var r=y._convertData(n);c.extend(!0,this.defaults,r)},new n}),e.define("select2/options",["require","jquery","./defaults","./utils"],function(r,d,i,p){function e(e,t){if(this.options=e,null!=t&&this.fromElement(t),null!=t&&(this.options=i.applyFromElement(this.options,t)),this.options=i.apply(this.options),t&&t.is("input")){var n=r(this.get("amdBase")+"compat/inputData");this.options.dataAdapter=p.Decorate(this.options.dataAdapter,n)}}return e.prototype.fromElement=function(e){var t=["select2"];null==this.options.multiple&&(this.options.multiple=e.prop("multiple")),null==this.options.disabled&&(this.options.disabled=e.prop("disabled")),null==this.options.dir&&(e.prop("dir")?this.options.dir=e.prop("dir"):e.closest("[dir]").prop("dir")?this.options.dir=e.closest("[dir]").prop("dir"):this.options.dir="ltr"),e.prop("disabled",this.options.disabled),e.prop("multiple",this.options.multiple),p.GetData(e[0],"select2Tags")&&(this.options.debug&&window.console&&console.warn&&console.warn('Select2: The `data-select2-tags` attribute has been changed to use the `data-data` and `data-tags="true"` attributes and will be removed in future versions of Select2.'),p.StoreData(e[0],"data",p.GetData(e[0],"select2Tags")),p.StoreData(e[0],"tags",!0)),p.GetData(e[0],"ajaxUrl")&&(this.options.debug&&window.console&&console.warn&&console.warn("Select2: The `data-ajax-url` attribute has been changed to `data-ajax--url` and support for the old attribute will be removed in future versions of Select2."),e.attr("ajax--url",p.GetData(e[0],"ajaxUrl")),p.StoreData(e[0],"ajax-Url",p.GetData(e[0],"ajaxUrl")));var n={};function r(e,t){return t.toUpperCase()}for(var i=0;i<e[0].attributes.length;i++){var o=e[0].attributes[i].name,s="data-";if(o.substr(0,s.length)==s){var a=o.substring(s.length),l=p.GetData(e[0],a);n[a.replace(/-([a-z])/g,r)]=l}}d.fn.jquery&&"1."==d.fn.jquery.substr(0,2)&&e[0].dataset&&(n=d.extend(!0,{},e[0].dataset,n));var c=d.extend(!0,{},p.GetData(e[0]),n);for(var u in c=p._convertData(c))-1<d.inArray(u,t)||(d.isPlainObject(this.options[u])?d.extend(this.options[u],c[u]):this.options[u]=c[u]);return this},e.prototype.get=function(e){return this.options[e]},e.prototype.set=function(e,t){this.options[e]=t},e}),e.define("select2/core",["jquery","./options","./utils","./keys"],function(i,c,u,r){var d=function(e,t){null!=u.GetData(e[0],"select2")&&u.GetData(e[0],"select2").destroy(),this.$element=e,this.id=this._generateId(e),t=t||{},this.options=new c(t,e),d.__super__.constructor.call(this);var n=e.attr("tabindex")||0;u.StoreData(e[0],"old-tabindex",n),e.attr("tabindex","-1");var r=this.options.get("dataAdapter");this.dataAdapter=new r(e,this.options);var i=this.render();this._placeContainer(i);var o=this.options.get("selectionAdapter");this.selection=new o(e,this.options),this.$selection=this.selection.render(),this.selection.position(this.$selection,i);var s=this.options.get("dropdownAdapter");this.dropdown=new s(e,this.options),this.$dropdown=this.dropdown.render(),this.dropdown.position(this.$dropdown,i);var a=this.options.get("resultsAdapter");this.results=new a(e,this.options,this.dataAdapter),this.$results=this.results.render(),this.results.position(this.$results,this.$dropdown);var l=this;this._bindAdapters(),this._registerDomEvents(),this._registerDataEvents(),this._registerSelectionEvents(),this._registerDropdownEvents(),this._registerResultsEvents(),this._registerEvents(),this.dataAdapter.current(function(e){l.trigger("selection:update",{data:e})}),e.addClass("select2-hidden-accessible"),e.attr("aria-hidden","true"),this._syncAttributes(),u.StoreData(e[0],"select2",this),e.data("select2",this)};return u.Extend(d,u.Observable),d.prototype._generateId=function(e){return"select2-"+(null!=e.attr("id")?e.attr("id"):null!=e.attr("name")?e.attr("name")+"-"+u.generateChars(2):u.generateChars(4)).replace(/(:|\.|\[|\]|,)/g,"")},d.prototype._placeContainer=function(e){e.insertAfter(this.$element);var t=this._resolveWidth(this.$element,this.options.get("width"));null!=t&&e.css("width",t)},d.prototype._resolveWidth=function(e,t){var n=/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;if("resolve"==t){var r=this._resolveWidth(e,"style");return null!=r?r:this._resolveWidth(e,"element")}if("element"==t){var i=e.outerWidth(!1);return i<=0?"auto":i+"px"}if("style"!=t)return"computedstyle"!=t?t:window.getComputedStyle(e[0]).width;var o=e.attr("style");if("string"!=typeof o)return null;for(var s=o.split(";"),a=0,l=s.length;a<l;a+=1){var c=s[a].replace(/\s/g,"").match(n);if(null!==c&&1<=c.length)return c[1]}return null},d.prototype._bindAdapters=function(){this.dataAdapter.bind(this,this.$container),this.selection.bind(this,this.$container),this.dropdown.bind(this,this.$container),this.results.bind(this,this.$container)},d.prototype._registerDomEvents=function(){var t=this;this.$element.on("change.select2",function(){t.dataAdapter.current(function(e){t.trigger("selection:update",{data:e})})}),this.$element.on("focus.select2",function(e){t.trigger("focus",e)}),this._syncA=u.bind(this._syncAttributes,this),this._syncS=u.bind(this._syncSubtree,this),this.$element[0].attachEvent&&this.$element[0].attachEvent("onpropertychange",this._syncA);var e=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;null!=e?(this._observer=new e(function(e){i.each(e,t._syncA),i.each(e,t._syncS)}),this._observer.observe(this.$element[0],{attributes:!0,childList:!0,subtree:!1})):this.$element[0].addEventListener&&(this.$element[0].addEventListener("DOMAttrModified",t._syncA,!1),this.$element[0].addEventListener("DOMNodeInserted",t._syncS,!1),this.$element[0].addEventListener("DOMNodeRemoved",t._syncS,!1))},d.prototype._registerDataEvents=function(){var n=this;this.dataAdapter.on("*",function(e,t){n.trigger(e,t)})},d.prototype._registerSelectionEvents=function(){var n=this,r=["toggle","focus"];this.selection.on("toggle",function(){n.toggleDropdown()}),this.selection.on("focus",function(e){n.focus(e)}),this.selection.on("*",function(e,t){-1===i.inArray(e,r)&&n.trigger(e,t)})},d.prototype._registerDropdownEvents=function(){var n=this;this.dropdown.on("*",function(e,t){n.trigger(e,t)})},d.prototype._registerResultsEvents=function(){var n=this;this.results.on("*",function(e,t){n.trigger(e,t)})},d.prototype._registerEvents=function(){var n=this;this.on("open",function(){n.$container.addClass("select2-container--open")}),this.on("close",function(){n.$container.removeClass("select2-container--open")}),this.on("enable",function(){n.$container.removeClass("select2-container--disabled")}),this.on("disable",function(){n.$container.addClass("select2-container--disabled")}),this.on("blur",function(){n.$container.removeClass("select2-container--focus")}),this.on("query",function(t){n.isOpen()||n.trigger("open",{}),this.dataAdapter.query(t,function(e){n.trigger("results:all",{data:e,query:t})})}),this.on("query:append",function(t){this.dataAdapter.query(t,function(e){n.trigger("results:append",{data:e,query:t})})}),this.on("keypress",function(e){var t=e.which;n.isOpen()?t===r.ESC||t===r.TAB||t===r.UP&&e.altKey?(n.close(),e.preventDefault()):t===r.ENTER?(n.trigger("results:select",{}),e.preventDefault()):t===r.SPACE&&e.ctrlKey?(n.trigger("results:toggle",{}),e.preventDefault()):t===r.UP?(n.trigger("results:previous",{}),e.preventDefault()):t===r.DOWN&&(n.trigger("results:next",{}),e.preventDefault()):(t===r.ENTER||t===r.SPACE||t===r.DOWN&&e.altKey)&&(n.open(),e.preventDefault())})},d.prototype._syncAttributes=function(){this.options.set("disabled",this.$element.prop("disabled")),this.options.get("disabled")?(this.isOpen()&&this.close(),this.trigger("disable",{})):this.trigger("enable",{})},d.prototype._syncSubtree=function(e,t){var n=!1,r=this;if(!e||!e.target||"OPTION"===e.target.nodeName||"OPTGROUP"===e.target.nodeName){if(t)if(t.addedNodes&&0<t.addedNodes.length)for(var i=0;i<t.addedNodes.length;i++){t.addedNodes[i].selected&&(n=!0)}else t.removedNodes&&0<t.removedNodes.length&&(n=!0);else n=!0;n&&this.dataAdapter.current(function(e){r.trigger("selection:update",{data:e})})}},d.prototype.trigger=function(e,t){var n=d.__super__.trigger,r={open:"opening",close:"closing",select:"selecting",unselect:"unselecting",clear:"clearing"};if(void 0===t&&(t={}),e in r){var i=r[e],o={prevented:!1,name:e,args:t};if(n.call(this,i,o),o.prevented)return void(t.prevented=!0)}n.call(this,e,t)},d.prototype.toggleDropdown=function(){this.options.get("disabled")||(this.isOpen()?this.close():this.open())},d.prototype.open=function(){this.isOpen()||this.trigger("query",{})},d.prototype.close=function(){this.isOpen()&&this.trigger("close",{})},d.prototype.isOpen=function(){return this.$container.hasClass("select2-container--open")},d.prototype.hasFocus=function(){return this.$container.hasClass("select2-container--focus")},d.prototype.focus=function(e){this.hasFocus()||(this.$container.addClass("select2-container--focus"),this.trigger("focus",{}))},d.prototype.enable=function(e){this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("enable")` method has been deprecated and will be removed in later Select2 versions. Use $element.prop("disabled") instead.'),null!=e&&0!==e.length||(e=[!0]);var t=!e[0];this.$element.prop("disabled",t)},d.prototype.data=function(){this.options.get("debug")&&0<arguments.length&&window.console&&console.warn&&console.warn('Select2: Data can no longer be set using `select2("data")`. You should consider setting the value instead using `$element.val()`.');var t=[];return this.dataAdapter.current(function(e){t=e}),t},d.prototype.val=function(e){if(this.options.get("debug")&&window.console&&console.warn&&console.warn('Select2: The `select2("val")` method has been deprecated and will be removed in later Select2 versions. Use $element.val() instead.'),null==e||0===e.length)return this.$element.val();var t=e[0];i.isArray(t)&&(t=i.map(t,function(e){return e.toString()})),this.$element.val(t).trigger("change")},d.prototype.destroy=function(){this.$container.remove(),this.$element[0].detachEvent&&this.$element[0].detachEvent("onpropertychange",this._syncA),null!=this._observer?(this._observer.disconnect(),this._observer=null):this.$element[0].removeEventListener&&(this.$element[0].removeEventListener("DOMAttrModified",this._syncA,!1),this.$element[0].removeEventListener("DOMNodeInserted",this._syncS,!1),this.$element[0].removeEventListener("DOMNodeRemoved",this._syncS,!1)),this._syncA=null,this._syncS=null,this.$element.off(".select2"),this.$element.attr("tabindex",u.GetData(this.$element[0],"old-tabindex")),this.$element.removeClass("select2-hidden-accessible"),this.$element.attr("aria-hidden","false"),u.RemoveData(this.$element[0]),this.$element.removeData("select2"),this.dataAdapter.destroy(),this.selection.destroy(),this.dropdown.destroy(),this.results.destroy(),this.dataAdapter=null,this.selection=null,this.dropdown=null,this.results=null},d.prototype.render=function(){var e=i('<span class="select2 select2-container"><span class="selection"></span><span class="dropdown-wrapper" aria-hidden="true"></span></span>');return e.attr("dir",this.options.get("dir")),this.$container=e,this.$container.addClass("select2-container--"+this.options.get("theme")),u.StoreData(e[0],"element",this.$element),e},d}),e.define("jquery-mousewheel",["jquery"],function(e){return e}),e.define("jquery.select2",["jquery","jquery-mousewheel","./select2/core","./select2/defaults","./select2/utils"],function(i,e,o,t,s){if(null==i.fn.select2){var a=["open","close","destroy"];i.fn.select2=function(t){if("object"==typeof(t=t||{}))return this.each(function(){var e=i.extend(!0,{},t);new o(i(this),e)}),this;if("string"!=typeof t)throw new Error("Invalid arguments for Select2: "+t);var n,r=Array.prototype.slice.call(arguments,1);return this.each(function(){var e=s.GetData(this,"select2");null==e&&window.console&&console.error&&console.error("The select2('"+t+"') method was called on an element that is not using Select2."),n=e[t].apply(e,r)}),-1<i.inArray(t,a)?this:n}}return null==i.fn.select2.defaults&&(i.fn.select2.defaults=t),o}),{define:e.define,require:e.require}}(),t=e.require("jquery.select2");return u.fn.select2.amd=e,t}); // </nowiki> sqetjg7vmcglb2y5wl8lfvir199aiom MediaWiki:Gadget-select2.min.css 8 35668 198563 2022-08-09T21:32:26Z ToprakM 19785 "/*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */ .select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-..." içeriğiyle yeni sayfa oluşturdu css text/css /*! Select2 4.0.12 | https://github.com/select2/select2/blob/master/LICENSE.md */ .select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px;padding:1px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} g1469rftkzxri386o3a0m1ueea3cqkp