Vikigezgin
trwikivoyage
https://tr.wikivoyage.org/wiki/Anasayfa
MediaWiki 1.47.0-wmf.24
first-letter
Ortam
Özel
Tartışma
Kullanıcı
Kullanıcı mesaj
Vikigezgin
Vikigezgin 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
Event
Event talk
Vikigezgin:Kullanıcı hakları adaylıkları
4
334
17862
17853
2026-10-24T16:49:33Z
Brightt11
1786
Restored revision 17803 by [[Special:Contributions/Brightt11|Brightt11]] ([[User talk:Brightt11|talk]]) (TwinkleGlobal)
17862
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
927ksyycynk3d8urfqbed07ajsvlvoy
17863
17862
2026-10-24T16:49:44Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Tarafsız ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi)
17863
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
mzmcwe87nw5xj5xfycqserj3ppeqooz
17865
17863
2026-10-24T17:06:51Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Destek ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17865
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
3uazetg5wjygavhhhdyt8xg3mcnypo4
17866
17865
2026-10-24T17:07:02Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Kısmi destek ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17866
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} tedt [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
sh3ze9nk1g8ctvgp2zk9amtsuvozqth
17867
17866
2026-10-24T17:07:10Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17867
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} tedt [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
8c7psxuejldbpl0s1e7q1ww9j2ovedl
17868
17867
2026-10-24T17:07:20Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Kısmi karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17868
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} tedt [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
1bt2p83hvt6ji2lntya5vacf51gat5f
17869
17868
2026-10-24T17:07:30Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Yorum ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17869
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} tedt [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
1luakky5wqf2kirssht619q7uviqgox
17873
17869
2026-10-24T17:14:59Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Kısmen karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17873
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} tedt [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmen karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
jy9pn08t8ssswq4i5v9rwb3lmxe9ndc
17874
17873
2026-10-24T17:15:35Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Kısmen karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17874
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} tedt [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmen karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmen karşı}} tekrar test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
3isajlelhbo25rggrhchp43whwf5s8r
17875
17874
2026-10-24T17:15:52Z
Brightt11
1786
/* Hizmetli adayı Örnek */
17875
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
927ksyycynk3d8urfqbed07ajsvlvoy
17876
17875
2026-10-24T17:15:57Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17876
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
jnz59wer6et1zgwcovky0o3cji5udck
17879
17876
2026-10-24T19:14:28Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17879
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
8ofzrk6ap9ksppeet68mz3dbazlcx62
17880
17879
2026-10-24T19:15:04Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Kısmi destek ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17880
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
0ewrcf0nkyzabrdfmo2jo1l0dngkkid
17882
17880
2026-10-24T19:18:32Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Destek ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17882
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.18, 24 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
dqa5qre5k86a6vxp2qvoptuldzmy69h
17883
17882
2026-10-24T19:20:13Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Yorum ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17883
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.18, 24 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.20, 24 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
guqlk7ckjk0t74metr1sk92hauk64nb
17886
17883
2026-10-24T19:21:33Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Karşı ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)
17886
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.18, 24 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.20, 24 Ekim 2026 (UTC)
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.21, 24 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
fof3r480eesk4nam3fvs5nhjgv6k3nr
17887
17886
2026-10-24T19:21:53Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Tarafsız ([[Kullanıcı:Brightt11/Oyver.js|Oyver (beta)]] ile görüş belirtildi.)
17887
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.18, 24 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.20, 24 Ekim 2026 (UTC)
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.21, 24 Ekim 2026 (UTC)
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.21, 24 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
spzvizqy9co66ymec6czpju0emowoxj
17888
17887
2026-10-24T19:46:39Z
Brightt11
1786
/* Hizmetli adayı Örnek */ Destek ([[Kullanıcı:Brightt11/Oyver.js|Oyver (beta)]] ile görüş belirtildi.)
17888
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
=== Hizmetli adayı [[User:Örnek|Örnek]] ===
<div class="plainlinks">
{{Aday kullanıcı
|Kullanıcı= <!-- adayın veya sizin kullanıcı adınız -->
|Status= <!-- burayı değiştirmeyin -->
}}
</div>
::''20:09, 26 Ekim 2026 (UTC) tarihinde oylama bitiyor.''<!-- burayı değiştirmeyin -->
<!-- Adaylık açıklaması buraya gelecek -->
Adaylık gerekçesi. [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 20.09, 12 Ekim 2026 (UTC)
<!-- Adaylık alanı sonu, oylama alanı başlangıcı -->
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Karşı}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Kısmi destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)
* {{Destek}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.18, 24 Ekim 2026 (UTC)
* {{Yorum}} test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.20, 24 Ekim 2026 (UTC)
* {{Karşı}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.21, 24 Ekim 2026 (UTC)
* {{Tarafsız}} [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.21, 24 Ekim 2026 (UTC)
* {{Destek}} Tekrar test [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 19.46, 24 Ekim 2026 (UTC)
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
psyong90lh6xyrhuepgqirl5fbtg1ur
17889
17888
2026-10-24T20:07:28Z
Brightt11
1786
Restored revision 17700 by [[Special:Contributions/Brightt11|Brightt11]] ([[User talk:Brightt11|talk]]): Artık kullanıma hazır (TwinkleGlobal)
17889
wikitext
text/x-wiki
{{/Başlık}}
== Arayüz yöneticisi adayları ==
== Bürokrat adayları ==
== Hizmetli adayları ==
== Ayrıca bakınız ==
* [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv]]
* [[Vikigezgin:Hizmetliler]]
* [[Vikigezgin:Bürokratlar]]
* [[Özel:Listusers/sysop|Mevcut hizmetliler]]
{{kullanıcı grupları}}
os5286of3ywrqod0jarzo51cyiso1rz
Vikigezgin:Kullanıcı hakları adaylıkları/Başlık
4
1407
17858
17760
2026-10-24T16:23:16Z
Brightt11
1786
/* Haklar */
17858
wikitext
text/x-wiki
Bu sayfada kullanıcı hak adaylıkları yer almaktadır. Herhangi bir adaylık başvurusu oluşturmadan önce [[Vikigezgin: politika ve yönergeler|politika ve yönergelere]] aşina olup olmadığınızı gözden geçirmelisiniz. Kendinizi hazır hissettiğinizde bu sayfada herhangi bir yetki için adaylık sayfası oluşturabilirsiniz.
Adaylıklarda tartışma süresi '''14 gündür.''' Süre sonunda, bir hizmetli veya deneyimli bir kullanıcı adaylığı sonuçlandırır. Karşıt oyların fazla olması durumunda hizmetli, adaylığı erken kapatma inisiyatifine sahiptir.
== Arayüz yöneticilği ==
{{bilgi|type=warn|Wikimedia Vakfı Ofisi (WMF Office), arayüz yöneticilerinin iki aşamalı kimlik doğrulama kullanmasını zorunlu kılmıştır.}}
Arayüz yöneticileri, MediaWiki ad alanındaki genel metin sayfalarını ve CSS, JS, ve JSON sayfalarını düzenleyebilen kullanıcılardır. Aynı zamanda tüm CSS, JS ve JSON sayfalarını düzenleyebilen tek kullanıcı grubudur.
== Hizmetlilik ==
Hizmetliler, insanların potansiyel olarak zararlı olabilecek araçları güvenle emanet edebileceklerini düşündükleri kullanıcılardır. Hizmetli olmanın, kişinin yaptığı hizmetlerden ötürü hakedilmiş bir rütbe ya da ödül gibi düşünülmemesi gerekir.
Bir Vikiçelebi'nin [[Vikigezgin:Hizmetliler|hizmetli]] olabilmesi için, tarafsız olması, Vikigezgin yapısını biliyor olması ve grup çalışmasına uygun olması gerekir. Aynı zamanda problemler karşısında soğukkanlılığını koruması da önemli bir gerekliliktir. Tabii ki, bütün bu özelliklerini kullanıcı olarak yaptığı çalışmalarda göstermiş olması gerekmektedir.
Hizmetlilerden yüksek standartlarda davranış ve rehberlik yeteneği beklenir, zira diğer kullanıcılar yardım ve öğüt almak için sıklıkla hizmetlilerin kapısını çalarlar. Aynı zamanda hizmetlilik, ek görevler ve sorumluluklar da getirmektedir. Bu ek görevler ve sorumluluklar sadece hizmetlilerin yapabileceği şeyler olduğu için öncelikli olup, madde yazmak gibi işler ikinci planda kalır. Bu durumdan rahatsız olacaksanız şimdiden vazgeçmeniz en doğrusudur.
== Bürokratlar ==
Bazı hizmetliler ek olarak bürokrat sıfatına sahiptirler. Bürokratlar hizmetlilik görevlerinin yanı sıra özel fonksiyonlara da sahiptirler.
----
Topluluk bu yetkileri güvenilir kullanıcılara verirler, ve bu sebeple adayların, diğer kullanıcılar hakkında güvenilir olup olmadıklarına karar verebilecekleri kadar makul bir süre Vikigezgin'de veya diğer Wikimedia projelerinde bulunmuş olmaları gerekmekte.
'''Oylama aşaması ve sonuçlandırma''': Herhangi bir kullanıcı, kullanıcı hesabı olan bir başka kullanıcıyı aday gösterebilir. Kişinin kendisini aday göstermesi de mümkündür. [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv|Eski başvurulara]] bakarak topluluğun hangi beklentilerde olduğuna dair fikir sahibi olabilir ve böylece sizin başvurunuza nasıl bir tepki geleceğini anlamaya çalışabilirsiniz. Adaylıklar başvurunun yapıldığı andan itibaren 14 gün boyunca sayfada aktif olarak kalır ve bu süre zarfında kullanıcılar fikirlerini belirtir, sorular sorar ve yorumlarda bulunurlar. Bu sürenin sonunda bir [[Vikigezgin:H|hizmetli]] veya kıdemli bir kullanıcı ilgili başvuruyu sonuçlandırarak hizmetlilik için bir fikir birliğinin sağlanıp sağlanamadığına bakar.
'''Fikir belirtme ve yorumlama''': Kullanıcı hesabı olan her Vikigezgin kullanıcısı adaylara oy verip yorum yapabilir. Aday da kişilerin yorumlarını cevaplayabilir. Hile şüpheleri barındıran bazı yorumlar dikkate alınmayabilir; bunlar çok yeni yazarların, [[Vikigezgin:Kukla|''çorap'' kuklaların]] ve [[Vikigezgin:Kukla|''canlı'' kuklaların]] katılımları olabilir. Lütfen fikrinizi muhakemenize dair bir açıklama yazarak açıklayınız. Yorumunuz eğer uygun ve destekleyici kanıtlar taşıyorsa daha büyük önem arz edecektir.
== Aday olmak ==
Hizmetlilik veya diğer haklar için aday olmak veya başka bir kullanıcıyı aday göstermek için '''[[Vikigezgin:Kullanıcı_hakları_adaylıkları/Adaylık|bu sayfadaki]]''' yönergeleri takip etmelisiniz.
<div class="metadata" style="background-color: #CED8DF; margin: 2em 0 0 0; padding: 0 10px 0 10px; border: 1px solid #AAAAAA; font-family: 'Montserrat semibold', sans-serif;">
;Aday olma kriterleri
#En az 1 aydır üye olmak (Bürokratlık adaylığı için en az 6 ay)
#Yeterli değişiklik sayıları:
##Bürokratlık adaylığın geçerli olması için en az 500 değişiklik yapılmış olması gerekmektedir.
##Hizmetli ve Arayüz Yöneticiliği adaylığı için ise en az 250 değişiklik yeterlidir.
;Başvuru anı
#Adaylık gerekçesi
;Sonuç
#Oylama süresi en az '''14 gün''' sürecektir.
#Arayüz yöneticiliği ve hizmetlilik adaylğında en az '''5 oy''' ve %75 puan gereklidir.
#Bürokratlık adaylığında en az '''15 oy''' ve %80 puan gereklidir; %75 ila %80 puan arası ise topluluk kararına bağlıdır.
#Oylama kriterlerine sahip olan her Vikiçelebi oylamaya katılım sağlayabilir (bakınız: aşağıdaki notlar).
'''Notlar'''
*Vikiçelebiler, adaylıklarda sadece 1 oy kullanabilir.
*Aynı kullanıcı, birden fazla oy kullanırsa bütün oyları '''geçersiz''' sayılır.
*Eski başvurulara [[Vikigezgin:Kullanıcı hakları adaylıkları/Arşiv|bu]] sayfadan bakabilirsiniz.
</div>
[[Kategori:Vikigezgin panoları]]
byukx78cpigswktvd6ilu1t290sf4vi
Kullanıcı:Brightt11/İETT hatlarının listesi
2
4131
17890
15598
2026-10-24T22:01:21Z
Brightt11
1786
17890
wikitext
text/x-wiki
== Hatlar ==
{| class="wikitable sortable"
|-
! Hat ismi !! Tarife !! Bölge !! Transfer
|-
| 1 Kirazlıtepe - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 2 Bostancı - Harem || Standart || Anadolu || {{ulaşım sembol|istanbul|M8}}
|-
| 3 Burhaniye - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 3A Ünalan - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 3B Ünalan - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 4 Maltepe Sahili - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 5 Valievleri - Üsküdar || Standart || Anadolu ||
|-
| 6 Esatpaşa - Harem || Standart || Anadolu ||
|-
| 7 Topağacı - Ümraniye - Rasathane || Standart || Anadolu ||
|-
| 8 Valievleri - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 8A Batı Alaşehir / Fikirtepe - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 8E Esenevler - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}{{ulaşım sembol|istanbul|T3}}
|-
| 8K Tepeüstü - Alaşehir - Kozyatağı Metrosu|| Standart || Anadolu ||{{ulaşım sembol|istanbul|M5}}
|-
| 8Y Soyak Yenişehir - Yenisahra Metrosu|| Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 9A Atakent - Ümraniye Metrosu || Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 9ÇN Çekmeköy - Nişantepe || Standart || Anadolu ||
|-
| 9H Cumhuriyetköy / Hüseyinli - Çekmeköy || Standart || Anadolu ||
|-
| 9K Atatürk Mahallesi - Taşdelen - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 9S Yeşiltepe - Çekmeköy Metrosu - Atatürk Mahallesi || Standart || Anadolu || {{ulaşım sembol|istanbul|M5}} {{ulaşım sembol|istanbul|M13}}
|-
| 9KS Kasaba evleri - Necip Fazıl Metrosu || Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 9T Şahinbey - Altunizade Metrobüs || Standart || Anadolu || {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 10 Ümraniye Eğitim Araştırma Hastanesi - Ataşehir - Bostancı || Standart|| Anadolu|| {{ulaşım sembol|istanbul|M8}}
|-
| 10A Esatpaşa - Yeditepe Üniversitesi - Ferhatpaşa|| Standart || Anadolu ||
|-
| 10B Bostancı - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}{{ulaşım sembol|istanbul|M8}}
|-
| 10E Esatpaşa - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 10EK Esatpaşa - Ataşehir - Kozyatağı Metrosu|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 10G Ümraniye - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}{{ulaşım sembol|istanbul|M5}}
|-
| 11 Yenidoğan - Altunizade || Standart || Anadolu ||{{ulaşım sembol|istanbul|Metrobüs}}
|-
| 11A Alemdağ - Altunizade || Standart || Anadolu ||{{ulaşım sembol|istanbul|Metrobüs}}
|-
| 11BE Burhaniye - Üsküdar|| Standart || Anadolu || {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 11C Burhaniye - Üsküdar Marmaray|| Standart || Anadolu || {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 11ÇB Kavacık - Ümraniye || Standart || Anadolu ||
|-
| 11CÜ Burhaniye - Ümraniye Metrosu Ring|| Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 11D İnklap - Ümraniye Metro || Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 11E Esatpaşa - Üsküdar|| Standart || Anadolu ||
|-
| 11ES Esenevler - Acıbadem Metrobüs / Üsküdar|| Standart || Anadolu || {{ulaşım sembol|istanbul|metrobüs}}
|-
| 11G Yenidoğan - Necip Fazıl Metrosu|| Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 11H Ortaçeşme - Ümraniye || Standart || Anadolu ||
|-
| 11K Kazım Karabekir - Ümraniye Metro || Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| 11L Esatpaşa / Bulgurlu - Üsküdar|| Standart || Anadolu ||
|-
| 11M Evtaş Blokları - Bulgurlu || Standart || Anadolu ||
|-
| 11P Emek - Üsküdar|| Standart || Anadolu ||
|-
| 11R Reşadiye - Necip Fazıl || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 11SA Uğurmumcu / Samandıra - Yenidoğan Peron|| Standart || Anadolu ||
|-
| 11ST Dumlupınar - Ümraniye || Standart || Anadolu ||
|-
| 11T Acarlar Sitesi - Harem || Standart || Anadolu ||
|-
| 11Ü Esatpaşa / Ünalan - Üsküdar|| Standart || Anadolu ||
|-
| 11ÜS Sultanbeyli - Üsküdar || Standart || Anadolu ||
|-
| 11Y Yavuztürk - Üsküdar|| Standart || Anadolu ||
|-
| 12 Kadıköy - Üsküdar || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 12A Kadıköy - Üsküdar || Standart || Anadolu ||{{ulaşım sembol|istanbul|M4}}
|-
| 12C Üsküdar - Üsküdar Devlet Hastanesi|| Standart || Anadolu ||
|-
| 13 Ataşehir - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 13B Yenişehir - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 13FY Batı Alaşehir - Mevlana Metro|| Standart || Anadolu || {{ulaşım sembol|istanbul|M8}}
|-
| 13H Evtaş Blokları - Ümraniye Metro|| Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 13M Şerifali - Üsküdar|| Standart || Anadolu ||
|-
| 13Y Çakmak Mahallesi - Yenisahra - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14 Yenidoğan / Ümraniye - Kadıköy|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 14A Alemdağ - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14AK Alemdağ - Ziverbey|| Standart || Anadolu ||
|-
| 14B Adem Yavuz Mahallesi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14BK Çekmeköy / Parseller Mahallesi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M8}}
|-
| 14C Üsküdar Devlet hastanesi - Kadıköy|| Standart || Anadolu ||
|-
| 14CE Çekmeköy - Kadıköy || Standart || Anadolu ||{{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M5}}
|-
| 14D Dumlupınar / Kazım Karabekir - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14DK İnklap Mahallesi - Libadiye / Kadıköy|| Standart || Anadolu ||{{ulaşım sembol|istanbul|M4}}
|-
| 14E Kazım Karabekir - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14ES Esenşehir - Kadıköy|| Standart || Anadolu ||{{ulaşım sembol|istanbul|M4}}
|-
| 14F Küflüce - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14FD Ferah Mahallesi - Üsküdar Devlet Hastanesi|| Standart || Anadolu ||
|-
| 14K Kazım Karabekir - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14KS Sultanbeyli Gölet - Kozyatağı Metro|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M8}}
|-
| 14m Kavacık Yeni Camii - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14R Rasathane - Kadıköy || Standart || Anadolu ||{{ulaşım sembol|istanbul|M4}}
|-
| 14S Sultanbeyli - Kozyatağı Metro || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M8}}
|-
| 14ŞB Şahinbey - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14T Atatürk Mahallesi / Taşdelen - Kozyatağı Metro|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M8}}
|-
| 14Y Yavuztürk Mahallesi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 14YE Yavuztürk - Ümraniye - Emek Mahallesi|| Standart|| Anadolu ||
|-
| 14YK Yenidoğan / Şile Yolu - Ayrılıkçeşme|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| 15 Beykoz - Üsküdar || Standart || Anadolu ||
|-
| 15A Anadolu Kavşak - Kavacık || Standart || Anadolu ||
|-
| 15B Topağacı Mahallesi / Güzeltepe - Üsküdar|| Standart || Anadolu ||
|-
| 15BK Dereseki - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 15C Büyük Çamlıca Camii / Ferah Mahallesi - Üsküdar|| Standart || Anadolu ||
|-
| 15CA Büyük Çamlıca Camii / Bulgurlu Metro - Göztepe Köprüsü|| Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 15ÇB Kavacık - Çavuşbaşı / Çengeldere|| Standart || Anadolu ||
|-
| 15ÇK Güzeltepe - Kadıköy|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M8}}
|-
| 15D Anadolufeneri / Kaynarca / Dereski - Sultaniye || Standart || Anadolu||
|-
| 15E Tekke Mevkii - Üsküdar || Standart || Anadolu||
|-
| 15H Hekimbaşı - Üsküdar || Standart || Anadolu ||
|-
| 15K Kirazlıtepe - Üsküdar || Standart || Anadolu ||
|-
| 15KB Kavacık - Kozyatağı Metrosu || Standart || Anadolu || {{ulaşım sembol|istanbul|M8}}
|-
| 15KÇ Karanlıkdere / ÇAVUŞBAŞI - ÜSKÜDAR || Standart || Anadolu||
|-
| 15M Kavacık Yeni Camii - Üsküdar|| Standart || Anadolu||
|-
| 15N Arkboyu - Üsküdar|| Standart || Anadolu||
|-
| 15P Soğuksu Mahallesi - Üsküdar || Standart || Anadolu||
|-
| 15R Rasathane - Üsküdar|| Standart || Anadolu||
|-
| 15S Sultanmurat - Üsküdar|| Standart || Anadolu||
|-
| 15SD Ortaçeşme/Sultaniye-Dudullu İMES || Standart || Anadolu||
|-
| 15SK Sultanmurat - Kadıköy|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 15ŞN Şenevler - Üsküdar || Standart || Anadolu||
|-
| 15T Tokatköy - Üsküdar || Standart || Anadolu||
|-
| 15TA Türk Alman Üniversitesi - Kavacık || Standart || Anadolu||
|-
| 15TY Tokatköy/ Beykoz - Yenimahalle || Standart || Anadolu||
|-
| 15U Tufan- Üsküdar || Standart || Anadolu||
|-
| 15Y Beykoz Yenimahalle - Üsküdar || Standart || Anadolu||
|-
| 15YK Beykoz Yenimahalle - Kadıköy || Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 15Z Güzeltepe - Üsküdar || Standart || Anadolu||
|-
| 16A Pendik - Üsküdar || Standart || Anadolu||
|-
| 16D Altıkaynarca - Pendik - Kadıköy || Çift katlı || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| 16F Fındıklı Mahallesi - Harem || Standart || Anadolu||
|-
| 16KH Yenişehir - Marmara Üniversite Hastanesi - Kadıköy || Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 16M Acarlar / Ataşehir - Üsküdar || Standart || Anadolu || {{ulaşım sembol|istanbul|M5}}
|-
| 16U Uğurmumcu - Usküdar || Standart || Anadolu ||
|-
| 16YK Yeditepe Üniversitesi - Fındıklı Mahallesi - Kozyatağı Metrosu || Standart || Anadolu ||
|-
| 17 Pendik - Kadıköy || Standart || Anadolu || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| 17L Küçükyalı Lojmanları - Marmara Üniversitesi - Üstbostancı || Standart || Anadolu ||
|-
| 17S Uğurmumcu - Bostancı || Standart || Anadolu || {{ulaşım sembol|istanbul|M8}}
|-
| 18D Sultanbeyli - Kadıköy || Çift katlı|| Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 18K Sultanbeyli - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 18YS Yenidoğan / Samandıra - Üsküdar|| Standart || Anadolu ||
|-
| 19 Ferhatpaşa - Yeditepe Üniversitesi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19A Yenidoğan - Ayrılıkçeşme|| Standart || Anadolu ||
|-
| 19D Ümraniye - Bostancı || Standart || Anadolu || {{ulaşım sembol|istanbul|M8}}
|-
| 19E Yenidoğan / Ataşehir - Kozyatağı Metro|| Standart || Anadolu ||
|-
| 19EK Yenidoğan / Ataşehir - || Standart || Anadolu ||
|-
| 19ES Esenşehir - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19F Yeditepe Üniversitesi - Fındıklı Mahallesi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19FB Fındıklı Mahallesi - Bostancı|| Standart || Anadolu || {{ulaşım sembol|istanbul|M8}}
|-
| 19FS Ferhatpaşa - Soyak Yenişehir|| Standart || Anadolu ||
|-
| 19K Acarlar Sitesi - Kayışdağı - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19M Acarlar Sitesi / Ataşehir - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19S Yenidoğan / Sarıgazi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19SK Yenidoğan / Sarıgazi - Kozyatağı Metro|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}{{ulaşım sembol|istanbul|M8}}
|-
| 19T Ferhatpaşa - Kadıköy|| Standart || Anadolu||{{ulaşım sembol|istanbul|M4}}
|-
| 19V Veysel Karani / Samandıra - Kozyatağı Metro|| Standart || Anadolu||
|-
| 19Y Ferhatpaşa - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 19YK Yenidoğan - Kayışdağı || Standart || Anadolu ||
|-
| 20 Çifteçınarlar - Ümraniye Eğitim ve Araştırma Hastanesi|| Standart || Anadolu ||
|-
| 20D Sarıgazi - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 20E Esatpaşa - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 20K Kazım Karabekir - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 20Ü Ümraniye Tepeüstü - Kadıköy|| Standart || Anadolu || {{ulaşım sembol|istanbul|M4}}
|-
| 22 İstinye Dereiçi - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}}
|-
| 22B Bebek - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}}
|-
| 22RE Fatih Sultan Mehmet - Beşiktaş|| Standart || Avrupa||
|-
| 22 Hacıosman Metro - Havantepe|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 25A RUmelikavağı - Hacıosman Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 25C Tarabyaüstü / Ferahevler - Hacıosman Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 25E Sarıyer - Baltalimanı || Standart || Avrupa||
|-
| 25G Sarıyer - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 25S1 Hacıosman Metro - Sarıyer|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 25S2 Hacıosman Metro - Sarıyer|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 25Y Hacıosman Metro - Yeni Uyum|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 26 Dikilitaş - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 26A Fulya - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 26B Fulya - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}}
|-
| 27 Şirintepe - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}}
|-
| 27SE Seyrantepe - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 27T Şirintepe - Şişli|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 28 Topkapı / Edirnekapı - Beşiktaş|| Standart || Avrupa||
|-
| 28T Topkapı - Beşiktaş|| Standart || Avrupa||
|-
| 29 İstinye Dereiçi - Zincirlikuyu Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 29A Derbent Mahallesi - Beşiktaş || Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 29B Fatih Sultan Mehmet - 4. Levent|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 29C Tarabyaüstü - Kabataş|| Standart || Avrupa||{{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 29D Ferahevler - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|F1}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 29E Maslak Gazeteciler Sitesi - Beşiktaş|| Standart || Avrupa||
|-
| 29GM Maslak Gazeteciler Sitesi - 4. Levent|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 29M1 Hacıosman Metrosu - Ferahevler / İstinye|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 29M2 Hacıosman Metrosu - İstinye / Ferahevler|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 29Ş İstinye Dereiçi - Şişli|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 29T Tarabyaüstü - İstinye|| Standart || Avrupa||
|-
| 30A Beşiktaş - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 30D Ortaköy Dereboyu - Yenikapı || Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|U3}}
|-
| 30M Beşiktaş - Mecidiyeköy|| Ring - Tek bilet|| Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 31 Kuyumcukent - Yenikapı || Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|U3}}
|-
| 31E Kuyumcukent - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|m1a}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 31Y Toki Ayazma - Yenikapı || Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|U3}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| 32 Cevatpaşa - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 32A Cevatpaşa - Aksaray|| Standart || Avrupa||
|-
| 32M Cevatpaşa - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 32T Cevatpaşa - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 33 Giyimkent / Turgutreis - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 33B Giyimkent / Birlik Mahallesi - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 33E Çiftedutlar - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|T5}}
|-
| 33ES Giyimkent - Eminönü || Standart || Avrupa||{{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 33M Giyimkent - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 33TE Turgutreis - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 33TM Giyimkent / Turgutreis - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 33Y Giyimkent / Yüzyıl Mahallesi - Eminönü || Standart || Avrupa || {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 35 Kocamustafapaşa - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 35C Kocamustafapaşa - Taksim || Standart || Avrupa||{{ulaşım sembol|istanbul|T2}}
|-
| 35D Kocamustafapaşa - Balat || Standart || Avrupa||
|-
| 36 Gaziosmanpaşa Yenimahalle Metrosu - Aksaray || Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| 36A Cebeci - Vezneciler || Standart || Avrupa||
|-
| 36AS Taşoluk Peronlar - Sefaköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 36AY Arnavutköy - Yenibosna Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 36B Bolluca - Cebeci|| Standart || Avrupa||
|-
| 36C Arnavutköy - Cebeci|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M11}}
|-
| 36CB Cebeci - Habipler|| Standart || Avrupa||
|-
| 36CY Cebeci - Yenibosna Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 36D Arnavutköy - Deliklikaya || Standart || Avrupa|| {{ulaşım sembol|istanbul|M11}}
|-
| 36ES Sultangazi Peron - Aksaray|| Standart || Avrupa||
|-
| 36F Cebeci - Fenertepe/Olimpiyatköy Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M9}}
|-
| 36G Sultangazi Peron - Beşiktaş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 36HT Arnavutköy Fatih Mahallesi - Haraççı - Cebeci|| Standart || Avrupa||
|-
| 36KE Gaziosmanpaşa Yenimahalle Metrosu - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}{{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 36L Mescidi Selam - 4. Levent|| Standart || Avrupa||
|-
| 36M Cebeci - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 36S Habipler - Gaziosmanpaşa Yenimahalle Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| 36TC Taşoluk Peronlar - Cebeci|| Standart || Avrupa||
|-
| 36V Yayla - Vezneciler|| Standart || Avrupa||
|-
| 36Y Taşoluk Peronlar - Mahmutbey Metrosu - Yenikapı Marmaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|U3}} {{ulaşım sembol|istanbul|M3}}{{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M11}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| 36YS Yassıören - Arnavutköy || Standart || Avrupa||
|-
| 36Z Cebeci - Zincirlikuyu|| Standart || Avrupa||{{ulaşım sembol|istanbul|Metrobüs}}
|-
| <S>37M Çırçır Metro - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}</S>
|-
| <S>37T Çırçır Metro - Taksim|| Standart || Avrupa||{{ulaşım sembol|istanbul|T2}} {{ulaşım sembol|istanbul|M7}}</S>
|-
|<S> 37Y Çırçır Metro - Vezneciler|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}</S>
|-
| 38 Sultangazi Peron - Aksaray|| Standart || Avrupa||
|-
| 38B Sultangazi Peron - Vezneciler|| Standart || Avrupa||
|-
| 38E Gaziosmanpaşa Devlet Hastanesi - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
|<S> 38G Gaziosmanpaşa Devlet Hastanesi - Mecidiyeköy|| Standart || Avrupa|| </S>
|-
| 38H Zübeyde Hanım Mahallesi - Habipler|| Standart || Avrupa||
|-
| 38Z Zübeyde Hanım Mahallesi - Aksaray|| Standart || Avrupa||
|-
| 40 Rumelifeneri / Garipçe - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 40B Sarıyer - Beşiktaş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 40T İstinye Dereiçi - Taksim|| Standart || Avrupa||{{ulaşım sembol|istanbul|T2}}
|-
| 41 Sinpaş Sitesi - 4. Levent|| Standart || Avrupa || {{ulaşım sembol|istanbul|M2}}
|-
| 41A Ayazağa - 4. Levent|| || Standart || {{ulaşım sembol|istanbul|M2}}
|-
| 41AT Ayazağa - Davutpaşa Üniversitesi|| Standart || Avrupa || {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 41C Ayazağa - Sarıyer|| Standart || Avrupa ||
|-
| 41E Ayazağa - Kabataş|| Standart || Avrupa||
|-
| 41N Nişantaşı Üniversitesi - Maslak|| Standart || Avrupa||
|-
| 41SF Sarıyer - Fatih Sultan Mehmet|| Standart || Avrupa||
|-
| 41SM Ayazağa Mezarlık - 4. Levent|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 41ST Seyrantepe - Topkapı|| Standart || Avrupa||
|-
| 42 Bahçeköy / Ferahevler - Zincirlikuyu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 42K Sarıyer - Kazım Karabekir|| Standart || Avrupa||
|-
| 42KT Sarıyer - Kocataş|| Standart || Avrupa||
|-
| <S>42M Bahçeköy - Zincirlikuyu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}} </S>
|-
| 42T Bahçeköy - Baltalimanı || Standart || Avrupa||
|-
| 42Z Hacıosman Metrosu - Kazım Karabekir|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m2}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 43R Rumeli Hisarüstü - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 46Ç Kağıthane - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 46KT Kuştepe - Şişli || Standart || Avrupa||
|-
| 46T Çağlayan - Topkapı || Standart || Avrupa||
|-
| 47L Binevler - Hacıosman Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 48 Göktürk - Mecidiyeköy|| Standart || Avrupa||
|-
| <S>48A Göktürk - Kazlıçeşme Marmaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|B1}} {{ulaşım sembol|istanbul|U3}}</S>
|-
| 48C Göktürk - Çiftalan Köyü|| Standart || Avrupa||
|-
| 48D Göktürk - Hacıosman Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 48G Göktürk - Mescidi Selam|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}}
|-
| 48H Hamidiye Mahallesi - Şişli|| Standart || Avrupa||
|-
| 48K Kemerburgaz - Ağaçlı Köyü|| Standart || Avrupa||
|-
| 48KA Kemerburgaz - Arnavutköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m11}}
|-
| 48L Göktürk - 4. Levent Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m2}}
|-
| 48M Akpınar Köyü - Arnavutköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 48N Emniyettepe - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 48P Kemerburgaz - Akpınar Köyü|| Standart || Avrupa||
|-
| 48S Sadabat Evleri - Şişli || Standart || Avrupa||
|-
| 48T Hamidiye Mahallesi - Taksim|| Standart || {{ulaşım sembol|istanbul|T2}}
|-
| 48U Bahçeşehir Üniversitesi - Kemerburgaz|| Standart || Avrupa||
|-
|<S> 49G Sultangazi Peron - Küçükköy - Şişli|| Standart || Avrupa|| </S>
|-
|<S> 49GB Sultangazi Peron - Baraj Yolu - Şişli|| Standart || Avrupa|| </S>
|-
| 49Y Yeşilpınar - Zincirlikuyu|| Standart || Avrupa||
|-
| 50A Alibeyköy - Edirnekapı Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 50AT Cebeci - Gazi - Alibeyköy|| Standart || Avrupa||
|-
| 50B Alibeyköy - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}}
|-
| 50C Alibeyköy - Şişli|| Standart || Avrupa||
|-
| 50D Alibeyköy - Ayazağa|| Standart || Avrupa||
|-
| 50E Alibeyköy - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 50F Alibeyköy - 4. Levent Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 50H Alibeyköy - Hacıosman Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 50K Alibeyköy - Kazlıçeşme Marmaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| 50M Alibeyköy - Beşiktaş|| Standart || Avrupa||
|-
| 50N Alibeyköy - Taksim|| Standart || Avrupa||{{ulaşım sembol|istanbul|T2}}
|-
| 50P Çırçır - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 50R Alibeyköy - Cep Otogarı || Standart || Avrupa||
|-
| 50S Alibeyköy - Şişli|| Standart || Avrupa||
|-
| 50T Alibeyköy - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 50V Alibeyköy - Vezneciler|| Standart || Avrupa||
|-
| 50Y Alibeyköy - Yenikapı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|U3}}
|-
| 50Z Alibeyköy - Zincirlikuyu|| Standart || Avrupa||{{ulaşım sembol|istanbul|Metrobüs}}
|-
| 54Ç Çıksalın - Taksim || Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 54E Okmeydanı - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 54HŞ Hasköy - Şişli|| Standart || Avrupa||
|-
| 54K Hasköy - Kulaksız - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 54KT Kaptanpaşa - Dolapdere / Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 54ÖR Örnektepe - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 54P Piyalepaşa Mahallesi - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 54T Sabadat Evleri / Talatpaşa - Taksim|| Standart || Avrupa||{{ulaşım sembol|istanbul|T2}}
|-
| 54TE Sabadat Evleri / Talatpaşa - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 55 Gaziosmanpaşa - Şişli || Standart || Avrupa||
|-
| 55B Gaziosmanpaşa - Beşiktaş|| Standart || Avrupa||
|-
| 55ET Gaziosmanpaşa - Beşiktaş|| Standart || Avrupa||
|-
| 55T Gaziosmanpaşa - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 55Y Kağıthane Garaj - Yenibosna Metrosu|| Standart || Avrupa||
|-
| 57UL Beşiktaş - Kuruçeşmeüstü|| Standart || Avrupa||
|-
| 58A Poligon Mahallesi - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|t1}} {{ulaşım sembol|istanbul|t5}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 58N Fatih Sultan Mehmet - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|t1}} {{ulaşım sembol|istanbul|t5}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 58UL Ulus Mahallesi - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 59A Rumeli Hisarüstü - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 59CH Beşiktaş Arnavutköy Mahallesi - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 59HS Hacıosman Metrosu - Sarıyer Kampüsü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 59K Karayolları - Şişli|| Standart || Avrupa||
|-
| 59N Fatih Sultan Mehmet - Şişli || Standart || Avrupa||
|-
| 59R Rumeli Hisarüstü - Şişli|| Standart || Avrupa||
|-
| 59RH Rumeli Hisarüstü - Hacıosman Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 59RK Rumeli Hisarüstü - Sarıtepe Kampüs|| Standart || Avrupa||
|-
| 59RS Rumeli Hisarüstü - Sarıyer|| Standart || Avrupa||
|-
| 62 Kağıthane - Gültepe - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 62G Emniyettepe / Hamidiye - Beşiktaş|| Standart || Avrupa||
|-
| 62H Emniyettepe - Hacıosman Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 63 Kağıthane - Kabataş|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 64 Emniyettepe / Çeliktepe - Şişli|| Standart || Avrupa||
|-
| 65A Seyrantepe - Kağıthane Garaj|| Standart || Avrupa||
|-
| 65G Kağıthane Garaş / Gültepe - Şişli|| Standart || Avrupa||
|-
| 66 Gülbağ - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 66Z Zincirlidere - Şişli|| Standart || Avrupa||
|-
| 70 Kurtuluş / Dolapdere - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 70FE Feriköy - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 70FY Feriköy - Yenikapı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|U3}}
|-
| 70KE Kurtuluş - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 70KY Kurtuluş - Yenikapı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|U3}}
|-
| 71T Ataköy - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 72T Yeşilköy - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 72YT Cerrahpaşa Tıp Fakültesi Acil Durum Hastanesi - Yenikapı Etkinlik Alanı|| Standart || Avrupa||
|-
| 73 Taksim - Yenibosna Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|T2}}
|-
| 73B Florya - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 73F Florya - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}} {{ulaşım sembol|istanbul|T2}}
|-
| 73H Cerrahpaşa Tıp Fakültesi Acil Durum Hastanesi - Yenibosna Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M9}}
|-
| 74 Hilton - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 74A Gayrettepe - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 75O Esenler Otogar - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 76 Beylikdüzü - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M34}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 76A Kiptaş Vaditepe - Yenikapı || Standart || Avrupa||
|-
| 76B Avcılar Cihangir Mahallesi - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 76BA Avcılar Metrobüs - Büyükçekmece|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| <S>76C Büyükçekmece - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|Metrobüs}} </S>
|-
| 76D Bahçeşehir / Esenkent - Taksim|| Çift katlı|| Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}} {{ulaşım sembol|istanbul|T2}}
|-
| 76G Gürpınar Mahallesi - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 76GM Gürpınar - Beylikdüzü E5 Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 76O Avcılar Cihangir Mahallesi - Esenler Otogar|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 76TM Tepekent - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 76V Kiptaş Vaditepe - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|U3}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| 77 Yenikapı - Şişli || Standart || Avrupa||
|-
| 77A Vezneciler - Şişli || Standart || Avrupa||
|-
| 77Ç Çıksalım - Şişli || Standart || Avrupa||
|-
| 78 Metrokent - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 78B Fenertepe Peron / Başakşehir - Yenibosna Metrosu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M9}}
|-
| 78C Fenertepe Peron - Yunus Emre Mahallesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 78E Fenertepe Peron / Başakşehir - Kayabaşı Kiptaş Konutları|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 78F Fenertepe Peron / Başakşehir - Metrokent|| Standart || Avrupa||{{ulaşım sembol|istanbul|M3}}
|-
| 78G Fenertepe Peron / Başakşehir - Kayaşehir|| Standart || Avrupa||{{ulaşım sembol|istanbul|M3}}
|-
| 78H Fenertepe Peron / Başakşehir - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 78K Fenertepe Peron / Başakşehir - Kanuni Sultan Süleyman Eğitim ve Araştırma Hastanesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 78Ş Fenertepe Peron / Başakşehir - Kayaşehir|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 78ZB Fenertepe Peron / Başakşehir - Zeytinburnu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 79B Kayaşehir - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M3}}
|-
| 79C Kayaşehir - Cebeci|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 79E Kayaşehir - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|T5}} {{ulaşım sembol|istanbul|F2}}
|-
| 79F Kayaşehir - Yenibosna|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M3}}
|-
| 79FY Fenertepe Peronlar - Yenibosna|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M3}}
|-
| 79G Kayaşehir - Zeytinburnu|| Standart || Avrupa||{{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 79GE Güvercintepe - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|T1}} {{ulaşım sembol|istanbul|T5}}
|-
| 79K Kayaşehir - Yenibosna|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M9}}
|-
| 79KM Kayaşehir - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}} {{ulaşım sembol|istanbul|M3}}
|-
| 79KT Kayaşehir - Tekstilkent Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M3}}
|-
| 79Ş Şahintepe İGTOT - Topkapı|| Standart || Avrupa||
|-
| 79T Kayaşehir - Topkapı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 79Y Kayaşehir - Yenibosna|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M9}}
|-
| 80 Kazlıçeşme Marmaray - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}}
|-
| 80T Kazlıçeşme Marmaray - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|T2}}
|-
| 82 Kuyumcukent - Eminönü|| Standart || Avrupa||
|-
| 85C Davutpaşa YTÜ - Kazlıçeşme Marmaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Marmaray}}
|-
|<S> 85T Esenler Metro - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1B}} {{ulaşım sembol|istanbul|T2}}</S>
|-
| 86V Eyüpsultan - Vezneciler|| Standart || Avrupa||
|-
| 87 Topkapı / Edirnekapı - Taksim|| Standart || Avrupa||{{ulaşım sembol|istanbul|T2}}
|-
| 88 Sultangazi Peronlar - Topkapı|| Standart || Avrupa||
|-
| 88A Sultangazi Peronlar - Yenikapı Etkinlik Alanı|| Standart || Avrupa||
|-
| 89 Kanuni Sultan Eğitim ve Araştırma Hastanesi / Atakent - Aksaray|| Standart || Avrupa||
|-
| 89A Kanuni Sultan Eğitim ve Araştırma Hastanesi - Zeytinburnu|| Standart || Avrupa||
|-
| 89B Küçükçekmece - Aksaray|| Standart || Avrupa||{{ulaşım sembol|istanbul|Metrobüs}}
|-
| 89BS Bezdirganbahçe TOKİ - Sefaköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 89C İETT İkitelli Garajı / Başakşehir 4. Etap - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 89F Küçükçekmece - İstoç|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 89K Kanuni Sultan Eğitim ve Araştırma Hastanesi - Aksaray|| Standart || Avrupa||
|-
| 89M Mehmet Akif Mahallesi - Zeytinburnu|| Standart || Avrupa||
|-
| 89S Küçükçekmece Söğütlüçeşme - Zeytinburnu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 89T Kanuni Sultan Eğitim ve Araştırma Hastanesi / Atakent - Taksim|| Standart || Avrupa||{{ulaşım sembol|istanbul|T2}}
|-
| 89YB Kanuni Sultan Eğitim ve Araştırma Hastanesi / Atakent - Bakırköy|| Standart || Avrupa||
|-
| 90 Draman - Eminönü|| Standart || Avrupa||
|-
| 90B Draman - Aksaray|| Standart || Avrupa||
|-
| 91E Göztepe Mahallesi - Aksaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| 91M Bağcılar Fatih Mahallesi Yanyol - Mecidiyeköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|metrobüs}}
|-
| 92 Bağcılar Yenimahalle Metro - Eminönü || Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 92B Bağcılar Yenimahalle Metro - Aksaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 92C Haznedar - Eminönü || Standart || Avrupa||
|-
| 92K Bağcılar Yenimahalle Metro - Kirazlı - Aksaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|T4}}
|-
| 92M Çınar Mahallesi / Bağcılar Devlet Hastanesi - Mecidiyeköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|metrobüs}}
|-
| 92Ş Bağcılar Yenimahalle Metro - Mecidiyeköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|metrobüs}}
|-
| 92T Bağcılar Devlet Hastanesi - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 93 Zeytinburnu - Eminönü|| Standart || Avrupa||
|-
| 93M Zeytinburnu - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|metrobüs}}
|-
| 93T Zeytinburnu - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| <S>94 İbni Sina İlköğretim Okulu - Zeytinburnu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|metrobüs}}</S>
|-
| 97 15 Temmuz Mahallesi - Aksaray|| Standart || Avrupa||{{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 97A Basınsitesi - Eminönü|| Standart || Avrupa||
|-
| 97BT Kocasinan İtfaiye - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 97E Mahmutbey - Kazlıçeşme Marmaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 97G Bağcılar Yenimahalle Metro - Aksaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 97GE 15 Temmuz Mahallesi / Güneşli - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 97KZ Kocasinan - Zeytinburnu|| Standart || Avrupa||
|-
| 97M 15 Temmuz Mahallesi / Güneşli - Mecidiyeköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 98 Fenertepe - Bakırköy|| Standart || Avrupa||{{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|M9}}
|-
| 98A Göztepe Mahallesi - Bakırköy || Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|M7}}
|-
| 98AB Atakent / Halkalı - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|m9}} {{ulaşım sembol|istanbul|marmaray}} {{ulaşım sembol|istanbul|metrobüs}}
|-
| 98B Kuyumcukent - Bakırköy|| Standart || Avrupa||{{ulaşım sembol|istanbul|m1a}} {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|metrobüs}}
|-
| 98D Bağcılar Yenimahalle Metro - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 98E Basın Tesisleri - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}}
|-
| 98G Giyimkent / Turgutreis - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|M7}}
|-
| 98H Metrokent - Bakırköy|| Standart || Avrupa||
|-
| 98KM Fenertepe - Sefaköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 98M İstoç - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}}
|-
| 98MB Kanuni Sultan Eğitim ve Araştırma Hastanesi - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}}
|-
| 98T Kanuni Sultan Eğitim ve Araştırma Hastanesi - Atakent - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|m9}}
|-
| 98TB Küçükçekmece Fatih Mahallesi - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}}
|-
| 98Y Giyimkent / Yüzyıl - Bakırköy|| Standart || Avrupa||{{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|M7}}
|-
| 99A Gaziosmanpaşa - Eminönü|| Standart || Avrupa||
|-
| 121A Beykoz - Mecidiyeköy|| 2 tam bilet - 2. boğazgeç|| Avrupa - Anadolu||
|-
| 121B Kavacık - Mecidiyeköy|| 2 tam bilet - 2. boğazgeç|| Avrupa - Anadolu||
|-
| 121BS Sultaniye - Mecidiyeköy|| 2 tam bilet - 2. boğazgeç|| Avrupa - Anadolu||
|-
| 122C Tepeüstü - Mecidiyeköy|| 2 tam bilet - 2. boğazgeç|| Avrupa - Anadolu||
|-
| 122ÇK Şahinbey - Kavacık||Standart||Anadolu||
|-
| 122D Atatürk Mahallesi - Mecidiyeköy|| 2 tam bilet - 2. boğazgeç || Avrupa - Anadolu||
|-
| 122M Şahinbey - Mecidiyeköy|| 2 tam bilet - 2. boğazgeç|| Avrupa - Anadolu||
|-
| 122V Veysel Karani - 4. Levent Metro|| 2 tam bilet - 2. boğazgeç|| Avrupa - Anadolu|| {{ulaşım sembol|istanbul|M2}}
|-
| 122Y Çekmeköy - Mecidiyeköy|| 2 tam bilet - 1. boğazgeç || Avrupa - Anadolu||
|-
| 129L Kozyatağı - 4. Levent Metro|| 2 tam bilet - 1. boğazgeç|| Avrupa - Anadolu|| {{ulaşım sembol|istanbul|M2}}
|-
| 129T Kadıköy Bostancı - Taksim|| 2 tam bilet - 1. boğazgeç|| Avrupa - Anadolu|| {{ulaşım sembol|istanbul|M8}} {{ulaşım sembol|istanbul|T2}}
|-
| 130A Deniz Harp Okulu - Kadıköy|| Standart || Anadolu||
|-
| 130E Tuzla / Evora Konutları - Kartal Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 130Ş Şifa Mahallesi - Kadıköy|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 130ŞT Şifa Mahallesi - Tavşantepe Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 130T Aydınlı Toki - Tuzla|| Standart || Anadolu||
|-
| <S>131 Sultanbeyli - Ümraniye|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}}</S>
|-
| <S> 131A Ahmet Yesevi Mahallesi - Ümraniye|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}}</S>
|-
|<S> 131B Mimar Sinan Mahallesi - Ümraniye|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}}</S>
|-
| <S>131H Hilal Konutları - Tepeüstü|| Standart || Anadolu|| </S>
|-
| 131K Yeşiltepe - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 131SB Sultanbeyli Merkez - Sultanbeyli Yeni Devlet Hastanesi|| Standart || Anadolu||
|-
| 131T Atatürk Mahallesi / Taşdelen - Ümraniye|| Standart || Anadolu||
|-
| <S>131Ü Sultanbeyli - Estergon Caddesi - Ümraniye|| Standart || Anadolu|| </S>
|-
| 131V Veysel Karani - Kartal|| Standart || Anadolu||
|-
| 131Y Çekmeköy - Kartal|| Standart || Anadolu||
|-
| 131YS Sultanbeyli Devlet Hastanesi - Yenidoğan - Ümraniye|| Standart || Anadolu||
|-
| 132 Akfırat - Kartal|| Standart || Anadolu||
|-
| 132A Çamlık - Kartal|| Standart || Anadolu||
|-
| 132B Akfırat evleri - Kartal Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132C Sultanbeyli Gölet - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132ÇK Çekmeköy - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M5}}
|-
| 132D Kurtdoğmuş - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132E Emirli / Kurnaköy - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132F Esenler - Tavşantepe Metrosu - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132G Gözdağ - Pendik Yüksek Hızlı Tren / Pendik|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}{{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| 132K Yenişehir - Kartal|| Standart || Anadolu||
|-
| 132M Sultanbeyli Mimarsinan - Kartal Metro / Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132N Nişantepe - Kartal|| Standart || Anadolu||
|-
| 132P Veysel Karani - Sultanbeyli - Kartal|| Standart || Anadolu||
|-
| 132S Yenidoğan - Kartal|| Standart || Anadolu||
|-
| 132SB Sultanbeyli Devlet Hastanesi - Marmara Üniversitesi Başıbüyük Kampüsü || Standart || Anadolu||
|-
| 132T Tepeören - Kartal Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 132V Yenidoğan - Pendik Yüksek Hızlı Tren|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| 132Y Yenidoğan - Marmara Üniversitesi Başıbüyük Kampüsü|| Standart || Anadolu||
|-
| 132YM Yeşiltepe - Marmara Eğitim Köyü|| Standart || Anadolu||
|-
| 132Z Sultanbeyli Uzundere - Kartal|| Standart || Anadolu||
|-
| 133A Aydınlı Bahçeler - Kartal|| Standart || Anadolu||
|-
| 133AK Tepeören - Kartal|| Standart || Anadolu||
|-
| 133F Acarlar Sitesi - Maltepe - Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 133G Gülensu Mahallesi - Kartal|| Standart || Anadolu||
|-
| 133GP Göçbeyli - Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 133K Kurtköy Sanayi Mahallesi - Kartal|| Standart || Anadolu||
|-
| 133KT Aydınlı Toki - Kartal|| Standart || Anadolu||
|-
| 133M Tuzla OSB - Kafkale Tuzla Sahili|| Standart || Anadolu||
|-
| 133N Maltepe Üniversitesi - Maltepe Metro / Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 133P Tepeören - Tuzla|| Standart || Anadolu||
|-
| 133Ş Çağdaşkent / Şekerpınar - Kartal|| Standart || Anadolu||
|-
| 133T Deniz Harp Okulu - Maltepe Peronlar|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| 133TM Aydınlı Toki / Mimarsinan Mahallesi - Tuzla|| Standart || Anadolu||
|-
| 133Ü Gazi Bulvarı / Orhanlı - Pendik Metro / Yüksek Hızlı Tren / Pendik|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| 134 Viaport / Hilal Konutları - Kartal|| Standart || Anadolu||
|-
| 134CK Şeyhli Mezarlık / Cezaevi - Kartal|| Standart || Anadolu||
|-
| 134GK Uğurmumcu / Gümüşpınar - Kartal|| Standart || Anadolu||
|-
| 134UK Uğurmumcu - Kartal|| Standart || Anadolu||
|-
| 134YK Uğurmumcu - Yakacık - Kartal|| Standart || Anadolu||
|-
| 135 Poyrazköy - Sultaniye|| Standart || Anadolu||
|-
| 135A Acarkent - Kavacık|| Standart || Anadolu||
|-
| 135G Tokatköy - Çavuşbaşı|| Standart || Anadolu||
|-
| 135K Karlıtepe - Ortaçeşme|| Standart || Anadolu||
|-
| 135T Arkboyu - Tokatköy|| Standart || Anadolu||
|-
| 136 Değirmendere - Sultaniye|| Standart || Anadolu||
|-
| 136B Alman Üniversitesi - Kavacık / Hekimbaşı|| Standart || Anadolu||
|-
| 136R Riva - Kavacık|| Standart || Anadolu||
|-
| 136Z Ali Bahadır / Zerzevat - Sultaniye|| Standart || Avrupa||
|-
| 137 Sultaniye / Beykoz - Riva / Cumhuriyet Köyü|| Standart || Anadolu||
|-
| 138 Cumhuriyet Köyü / Ömerli Madenler - Ümraniye || Standart || Anadolu||
|-
| 138B Göllü / Ömerli Madenler - Ümraniye|| Standart || Anadolu||
|-
| 139 Şile - Üsküdar|| VIP Kademeli|| Anadolu||
|-
| 139A Üsküdar - Şile / Ağva|| VIP Kademeli|| Anadolu||
|-
| 139D Bereket Sitesi - Darlık|| Bölgesel|| Anadolu||
|-
| 139S Üsküdar - Sofular Köyü|| Bölgesel|| Anadolu||
|-
| 139T Tepeüstü - Şile|| Bölgesel|| Anadolu||
|-
| 141A Kanuni Sultan Eğitim ve Araştırma Hastanesi - Atakent|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| 141K Kanuni Sultan Eğitim ve Araştırma Hastanesi - Mahmutbey Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|n7}}
|-
| 141M Kanuni Sultan Eğitim ve Araştırma Hastanesi - Mecidiyeköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142 Boğazköy - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142A Boğazköy - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142B Kanuni Sultan Eğitim ve Araştırma Hastanesi - Büyükçekmece|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142E Esenyurt Kiptaş - Aksaray|| Standart || Avrupa||
|-
| 142ES İstanbul Üniversitesi Cerrahpaşa Kampüsü - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142F Yeşilkent - Avcılar|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142K Esenyurt Kiptaş - Avcılar|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 142T Kanuni Sultan Eğitim ve Araştırma Hastanesi - Tüyap Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 143 Küçükçekmece - İstoç|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| 144 Bahçekent - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 144A Deliklikaya - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 144B Deliklikaya - Yeşilbayır Köyü - Gürpınar Su Ürünleri Hali|| Standart || Avrupa||
|-
| 144H Deliklikaya - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 144K Ömerli Kiptaş Konutları - Esenkent|| Standart || Avrupa||
|-
| 144M Deliklikaya - Mahmutbey Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M9}}
|-
| 145 İhlas Marmara - Küçükçekmece|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 145M Beykent - Taksim ||Çift katlı - Ekspress || Avrupa || {{ulaşım sembol|istanbul|T2}} {{ulaşım sembol|istanbul|T4}}
|-
| 145T Beylikdüzü - Taksim|| Çift katlı - Ekspress|| Avrupa|| {{ulaşım sembol|istanbul|T2}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 146 Boğazköy - Bakırköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 146A Esenkent - Birlik Mahallesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| 146B Metrokent - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| 146F Fenertepe - Metrokent|| Standart || Avrupa||{{ulaşım sembol|istanbul|M3}}
|-
| 146K Fenertepe - Birlik Mahallesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M9}}
|-
| 146M Metrokent - Mecidiyeköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 146T Boğazköy - Yenikapı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1a}} {{ulaşım sembol|istanbul|M1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|U3}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| 147 İGTOT - Avcılar Cihangir Mahallesi|| Standart || Avrupa||
|-
| 150 Hacıosman Metro - Rumelifeneri|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 151 Hacıosman Metro - Kilyos / Demirciköy || Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 152 Hacıosman Metro - Zekeriyaköy / Kısırkaya || Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 153 Bahçeköy - Sarıyer|| Standart || Avrupa||
|-
| 154 Hacıosman Metro - Koç Üniversitesi Kampüsü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| 251 Pendik - Mecidiyeköy || 2 tam bilet 1. boğazgeç|| Avrupa|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| 256 Yeditepe Üniversitesi / Ataşehir - Taksim|| 2 tam bilet 1. boğazgeç|| Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| 300 Silivri - Tüyap|| Bölgesel - Kademeli || Avrupa||
|-
| 300B Silivri Büyükçavuşlu - Tüyap|| Bölgesel - Kademeli|| Avrupa||
|-
| 300C Silivri Çanta - Tüyap|| Bölgesel - Kademeli|| Avrupa||
|-
| 300D Değirmenköy - Tüyap|| Bölgesel - Kademeli|| Avrupa||
|-
| 300G Gümüşkaya - Tüyap|| Bölgesel - Kademeli|| Avrupa||
|-
| 300M Silivri Mimarsinan / Kavaklı - Tüyap|| Bölgesel - Kademeli|| Avrupa||
|-
| 300S Silivri Cezaevi - Tüyap|| Bölgesel - Kademeli|| Avrupa||
|-
| 303A Silivri - Avcılar Metrobüs|| Bölgesel - Kademeli|| Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 303B Silivri Cezaevi - Esenler Otogar|| Bölgesel - Kademeli|| Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 336 Arnavutköy - Eminönü|| Standart || Avrupa||
|-
| 336A Balaban - Mescid-i Selam|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}}
|-
| 336E Sultançifliği - Eminönü|| Standart || Avrupa||
|-
| 336G Taşoluk Peronlar - Tekstilkent Metro || Standart || Avrupa|| {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M11}} {{ulaşım sembol|istanbul|T4}}
|-
| 336H Hadımköy Akpınar - Mescid-i Selam|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}}
|-
| 336K Yeniköy - Mescid-i Selam|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T4}}
|-
| 336M Arnavutköy - Mecidiyeköy Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 336Y Cebeci Peronlar - Yenikapı Marmaray|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}} {{ulaşım sembol|istanbul|b1}} {{ulaşım sembol|istanbul|t4}}
|-
| 400A Beykent - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 401 Çatalca - Avcılar Metrobüs||Bölgesel - Kademeli|| Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 401T Tepekent - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 402 Binkılıç - Çatalca || Bölgesel - Kademeli|| Avrupa||
|-
| 403 Çiflikköy - Çatalca|| Bölgesel - Kademeli|| Avrupa||
|-
| 404 Yalıköy - Çatalca|| Bölgesel - Kademeli|| Avrupa||
|-
| 418 Hadımköy Akpınar - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 429A Kıraç - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 448 Güzelce - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 458 Yedikardeşler Camii / Gürpınar - İstanbul Üniversitesi Cerrahpaşa Avcılar Kampüsü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 500L Levent - Cevizlibağ|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 500L 4. Levent - Cevizlibağ (yakında)|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 500T Tuzla Şifa Mahallesi - Cevizlibağ / Zeytinburnu Çırpıcı|| 2 tam bilet 2. boğazgeç|| Avrupa - Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|T4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 500T Tuzla Şifa Mahallesi - 4. Levent (yakında)|| 2? bilet 2. boğazgeç - 500L aktarması ücretsiz|| Avrupa - Anadolu|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 522 Alemdağ - Mecidiyeköy Mezarlık || 2 tam bilet 1. boğazgeç|| Avrupa Anadolu|| {{ulaşım sembol|istanbul|M2}}{{ulaşım sembol|istanbul|M7}}
|-
| 522ST Sultanbeyli - Mecidiyeköy Mezarlık|| 2 tam bilet 1. boğazgeç||Avrupa - Anadolu || {{ulaşım sembol|istanbul|M2}}{{ulaşım sembol|istanbul|M7}}
|-
| 559C Rumeli Hisarüstü - Taksim || Standart || Avrupa || {{ulaşım sembol|istanbul|T2}}
|-
| 622 Yenidoğan - Mecidiyeköy Mezarlık|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M2}}{{ulaşım sembol|istanbul|M7}}
|-
| BM4 Kavaklı - Haramidere Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| BM5 Sahil Mahallesi - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| BM6 Beylikdüzü - Haramidere|| Standart || Avrupa||{{ulaşım sembol|istanbul|Metrobüs}}
|-
| BM7 Haramidere - Yakuplu - Beylikdüzü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| BM8 Gürpınar - Adnan Kahveci Mahallesi - Cumhuriyet Mahallesi Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| BN1 Halkalı - Eminönü|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Marmaray}}
|-
| ÇM41 Çekmeköy - Necip Fazıl|| Standart || Anadolu||
|-
| ÇM42 Şahinbey - Çekmeköy Metro - Emek|| Standart || Anadolu||
|-
| ÇM43 Atatürk Mahallesi - Necip Fazıl|| Standart || Anadolu||
|-
| ÇM44 Nişantepe - Çekmeköy Metro|| Standart || Anadolu||
|-
| D1 Tepeüstü - Polonezköy / Cumhuriyet Köyü || Yaz Tarifeli - Standart|| Anadolu||
|-
| DS1 Dudullu Organize Sanayi Bölgesi - Dudullu Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}} {{ulaşım sembol|istanbul|M8}}
|-
| DS2 Dudullu Organize Sanayi Bölgesi - Dudullu Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}} {{ulaşım sembol|istanbul|M8}}
|-
| DT1 Ortaköy - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| DT2 Ortaköy - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| E-56 Ispartakule - Taksim|| Çift katlı - 2 tam bilet || Avrupa|| {{ulaşım sembol|istanbul|T4}}
|-
| E-57 Esenkent - Bahçeşehir - Bakırköy || Çift katlı - 2 tam bilet|| Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| E-58 Bahçeşehir - Mecidiyeköy|| Çift katlı - 2 tam bilet || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| E-59 Boğazköy - Taksim|| Çift katlı - 2 tam bilet|| Avrupa|| {{ulaşım sembol|istanbul|T2}} {{ulaşım sembol|istanbul|T4}}
|-
| EL2 Emirgan - 4. Levent|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| EM1 Eminönü - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| EM2 Eminönü - Taksim|| Standart || Avrupa|| {{ulaşım sembol|istanbul|T2}}
|-
| ER1 Kadıköy - Erenköy|| Ring - Tek bilet|| Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| ER2 Kadıköy - Erenköy|| Ring - Tek bilet|| Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| ES1 Esenyurt Belediye - Beylikdüzü Devlet Hastanesi / Beykent|| Standart || Avrupa||
|-
| ES2 Tüyap - Akçaburgaz|| Standart || Avrupa||
|-
| ES3 Esenyurt Devlet Hastanesi - Haramidere || Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| ES4 Esenyurt Kiptaş 4. Etap - Haramidere|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| FB1 Kadıköy - Fenerbahçe|| Ring - Tek bilet|| Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| FB2 Kadıköy - Fenerbahçe|| Ring - Tek bilet|| Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| HM1 Hacıosman Metro - 4. Levent Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| HM2 Konaklar - 4. Levent Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M2}}
|-
| HM3 Hürriyet - Şişli|| Standart || Avrupa||
|-
| HM4 Levent Basın Sitesi - Şişli|| Standart || Avrupa||
|-
| HT1 Kanuni Sultan Eğitim ve Araştırma Hastanesi - Üçyüzlü Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m1a}}
|-
| HT5 Kocatepe - Nur Sitesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m1a}} {{ulaşım sembol|istanbul|m1b}}
|-
| HT6 Batışehir - Kocatepe|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m1a}} {{ulaşım sembol|istanbul|m1b}}
|-
| HT10 Batışehir - Yenibosna Metro / Kuyumcukent|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1A}} {{ulaşım sembol|istanbul|m1b}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|m3}}{{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT11 Giyimkent - Tekstilkent Metro / Kuyumcukent || Standart || Avrupa|| {{ulaşım sembol|istanbul|M1A}} {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|m3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT12 Güneşli Basın Tesisler - Yenibosna Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1A}} {{ulaşım sembol|istanbul|M9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT13 Bölge İdare Mahkemesi / Bağcılar Yenimahalle Metro - Zeytinburnu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M1A}} {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT18 Hadımköy Akpınar Peronlar / İstanbul Üniversitesi Cerrahpaşa Kampüsü - Tüyap|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT19 İstanbul Üniversitesi Cerrahpaşa Kampüsü - Tüyap|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT20 Şahintepesi / İGTOT - Yenibosna Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m1a}} {{ulaşım sembol|istanbul|m9}}
|-
| HT29 Kıraç Yolu - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| HT48 Arel Üniversitesi - Tepekent - Avcılar Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|Metrobüs}}
|-
| K1 Kağıthane - Seyrantepe - Hamidiye Etfal|| Standart || Avrupa||
|-
| K2 Kağıthane - Seyrantepe - Hamidiye Etfal|| Standart || Avrupa||
|-
| K3 Kağıthane Garaj - Vadi İstanbul|| Standart || Avrupa||
|-
| KÇ2 Kanuni Sultan Eğitim ve Araştırma Hastanesi - Kartaltepe / Yenibosna Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m1a}} {{ulaşım sembol|istanbul|m9}}
|-
| KM2 Kavakpınar - Tavşantepe|| Standart || Anadolu||{{ulaşım sembol|istanbul|M4}}
|-
| KM3 Uğurmumcu - Yakacık Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM10 Aydınlı TOKİ / İçmeler - Pendik Metro / Yüksek Hızlı Tren - Kartal || Standart || Anadolu|| {{ulaşım sembol|türkiye|YHT}} {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM11 Aydınlı TOKİ - Pendik Köprü|| Standart || Anadolu||
|-
| KM12 Deniz Harp Okulu - Kartal Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| KM13 Tuzla - Pendik Metro / Yüksek Hızlı Tren - Pendik|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}{{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM14 Ahmet Yesevi - Tavşantepe Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM15 Yenişehir - Kartal Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM17 Tuzla Emlak Konutları - Tavşantepe Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M5}}
|-
| KM18 Sabancı Üniversitesi / Medeniyet Üniversitesi - Kurtköy Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM21 Hilal Konutları - Kartal Metro / Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM23 Kavakpınar - Kartal Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM23 Kavakpınar / Marmara Hastanesi - Pendik Metro / Yüksek Hızlı Tren / Pendik|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM24 Kavakpınar - Pendik Metro / Yüksek Hızlı Tren / Pendik|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM25 Yenişehir - Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM26 Çamlık Mahallesi - Pendik Metro / Yüksek Hızlı Tren / Pendik || Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM27 Yenişehir - Pendik Metro / Yüksek Hızlı Tren / Pendik|| Standart || Anadolu||{{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM28 Okan Üniversitesi - Kurtköy Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| KM29 Yenişehir - Marmara Hastanesi - Kartal Metro / Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM30 Kartal - Esenkent Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM31 Uğurmumcu - Kartal|| Standart || Anadolu||
|-
| KM32 Kurfalı - Kartal Metro / Kartal|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM33 Pendik Sahil - Maltepe Esenkent Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM34 Kartal Metro / Topselvi - Gülsuyu Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM35 Uğurmumcu - Kartal|| Standart || Anadolu||
|-
| KM36 Kurfalı - Cevizli|| Standart || Anadolu||
|-
| KM37 Hilal Konutları - Pendik Metro / Yüksek Hızlı Tren - Pendik|| Standart || Anadolu|| {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| KM41 Marmara Üniversitesi - Küçükyalı Metro - Başıbüyük Sağlık Kampüsü|| Standart || Anadolu||
|-
| KM42 Başıbüyük - Kartal|| Standart || Anadolu||
|-
| KM43 Maltepe Üniversitesi - Zümrütevler - Maltepe|| Standart || Anadolu||
|-
| KM44 Maltepe Üniversitesi - Siteler - Maltepe|| Standart || Anadolu||
|-
| KM45 Marmara Üniversitesi / Küçükyalı Metro - Mimar Sinan Öğrenci Yurdu - Maltepe Üniversitesi|| Standart || Anadolu||
|-
| KM46 Batı Alaşehir - Kozyatağı Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M8}}
|-
| KM47 Gülensu - Huzurevi Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM48 Esenkent - Huzurevi Metro|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM60 Veysel Karani - Kartal Metro / Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM61 Paşaköy / Samandıra - Kartal|| Standart || Anadolu||
|-
| KM70 Sultanbeyli - Kartal Metro - Cevizli|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M4}}
|-
| KM71 Yenidoğan - Cevizli|| Standart || Anadolu||
|-
| KM72 Pendik / Pendik Metro / Yüksek Hızlı Tren - Sultanbeyli Devlet Hastanesi|| Standart || Anadolu|| {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| <s>KRB3 Pendik Yüksek Hızlı Tren - Kurnaköy Kurban Pazarı</s>||<s> Geçici hat</s>|| <s>Anadolu</s>||<s> {{ulaşım sembol|türkiye|yüksekhızlıtren}}</s>
|-
| <S>MK2 Olimpiyatköy Metro - Şehir Hastanesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m9}}</S>
|-
| MK11 Olimpiyatköy Metro - Kayaşehir - Güvercintepe|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| MK12 Olimpiyatköy Metro - Güvercintepe - Kayaşehir|| Standart || Avrupa|| {{ulaşım sembol|istanbul|M3}}
|-
| MK13 Şahintepesi / İGTOT - Olimpiyatköy Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m9}}
|-
| MK14 Kiptaş Vaditepe - Olimpiyatköy Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m9}}
|-
| MK15 Boğazköy - Olimpiyatköy Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m9}}
|-
| MK16 Olimpiyatköy Metro - Küçükçekmece Metrobüs|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m9}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| MK19 Ayazma - Arenapark|| Standart || Avrupa||
|-
| MK22 Taşoluk - Şehir Hastanesi|| Standart || Avrupa||
|-
| MK31 Kanuni Sultan Eğiti ve Araştırma Hastanesi - Fenertepe || Standart || Avrupa||
|-
| MK42 15 Temmuz Mahallesi - Kirazlı Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m1b}}
|-
| MK49 Sultangazi - Kazım Karabekir Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m7}}
|-
| MK50 Sultangazi - Kazım Karabekir Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m7}}
|-
| MK53 Sultangazi - Giyimkent / Tekstilkent Metro|| Standart || Avrupa|| {{ulaşım sembol|istanbul|m7}}
|-
| MK97 Kerim Çavuşpaşa - Zeytinburnu|| Standart || Avrupa|| {{ulaşım sembol|istanbul|metrobüs}}
|-
| MR9 Atatürk Mahallesi - Ayrılıkçeşme|| Standart || Anadolu|| {{ulaşım sembol|istanbul|m5}} {{ulaşım sembol|istanbul|marmaray}} {{ulaşım sembol|istanbul|metrobüs}}
|-
|<S> MR10 Zeytinburnu - Kazlıçeşme|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}}</S>
|-
| MR11 Kazlıçeşme - Topkapı || Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}} {{ulaşım sembol|istanbul|metrobüs}}
|-
| MR20 Yenibosna Metro - Kazlıçeşme|| Standart || Avrupa||{{ulaşım sembol|istanbul|marmaray}}
|-
| MR40 Kanuni Sultan Eğitim ve Araştırma Hastanesi - Atakent - Halkalı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}}
|-
| MR42 Halkalı - Sefaköy|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}} {{ulaşım sembol|istanbul|metrobüs}}
|-
| MR50 Halkalı - Şehir Hastanesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}}
|-
| MR51 İstanbul Üniversitesi Cerrahpaşa Kampüsü / Bahçeşehir - Halkalı|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}}
|-
| MR52 Küçükçekmece Söğütlüçeşme - Halkalı - Şehir Hastanesi|| Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}}
|-
| MR52 İGTOT - Halkalı || Standart || Avrupa|| {{ulaşım sembol|istanbul|marmaray}}
|-
| MR61 Güzelyalı - Tuzla Devlet Hastanesi|| Standart || Anadolu||
|-
| PD1 Yenikapı - Beyazıt|| Besleme|| Avrupa||
|-
| SM1 Sultanbeyli - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM2 Ahmet Yesevi Mahallesi - Sancaktepe Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM3 Mimarsinan Mahallesi - Profesör Doktor Feriha Öz Hastanesi|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM4 Hilal Konutları - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM5 Sultanbeyli Orman Caddesi - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM6 Sultanbeyli Devlet Hastanesi - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM7 Yenidoğan - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM9 Kartal Metro - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M4}}{{ulaşım sembol|istanbul|M5}}
|-
| SM12 Maltepe MYO - Samandıra Merkez Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| SM13 Yenidoğan - Sancaktepe Metro|| Standart || Besleme|| {{ulaşım sembol|istanbul|M5}}
|-
| SM14 Ayazma Yaşam Vadisi - Sancaktepe Metro|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| TM1 Emniyettepe - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM2 Hamidiye - Güzeltepe - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM3 Hamidiye - Kağıthane - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM4 Göktürk - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM5 Alibeyköy - 5. Levent|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM6 Nur Sitesi - Fabrikalar|| Besleme || Avrupa||
|-
| TM7 Çırçır Metro - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM8 Akşemsettin - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM9 Gaziosmanpaşa Yenimahalle - Kazım Karabekir - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM10 Yeşilpınar - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM11 Yeşilpınar - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM12 Karadolap - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM13 Eyüpsultan - Gaziosmanpaşa - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM14 Gaziosmanpaşa Yenimahalle / Sarıgöl - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM15 Cebeci - Alibeyköy || Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM16 GOP Yenimahalle - Gaziosmanpaşa - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM17 Sultangazi - Gazi - Alibeyköy || Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM18 Mescid-i Selam - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-
| TM19 Zübeyde Hanım - Alibeyköy|| Besleme - Metro Entegre|| Avrupa|| {{ulaşım sembol|istanbul|M7}}
|-]]
|-
| UM11 Kirazlıtepe - Kısıklı Metro - Esatpaşa|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| UM13 Küçüksu / Yavuztürk - Ümraniye Eğitim ve Araşıtrma Hastanesi|| Standart || Anadolu||
|-
| UM36 Esenevler - Bulgurlu|| Standart || Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| UM40 Atatürk Mahallesi - Necip Fazıl|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| UM60 Sancaktepe - Necip Fazıl|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| UM61 Paşaköy - Necip Fazıl|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| UM62 Yenidoğan - Necip Fazıl|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M5}}
|-
| UM74 Sultanbeyli Devlet Hastanesi - Necip Fazıl - Dudullu OSB|| Besleme|| Anadolu|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M5}}
|}
== Depar hatlar ==
{| class="wikitable sortable" style="width: 100%;"
|-
! Hat adı !! Güzergah !! Bölge !! Garajın bulunduğu ilçe !! Aktarma
|-
| AVR1 || Güvercintepe Sapağı - Adalet Sarayı|| Avrupa || Küçükçekmece || {{ulaşım sembol|istanbul|M3}}
|-
| AVR2 ||
|-
| AVR3 ||
|-
| AVR3K ||
|-
| AND1A ||
|-
| AND1Ş ||
|-
| AND2K ||
|-
| AND2S ||
|-
| AND2Y ||
|}
== Hava ulaşım hatları ==
{| class="wikitable sortable" style="width: 100%;"
|-
! Hat ismi !! Tarife !! Aktarma
|-
| H1 Mahmutbey Metro - İstanbul Havalimanı|| 2 tam bilet - indirim geçmez|| {{ulaşım sembol|istanbul|M3}} {{ulaşım sembol|istanbul|M7}} {{ulaşım sembol|istanbul|M11}}
|-
| H2 Mecidiyeköy Metrobüs - İstanbul Havalimanı (Gece hattı) || 2 tam bilet - indirim geçmez|| {{ulaşım sembol|istanbul|M11}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| H3 Halkalı Marmaray - İstanbul Havalimanı || 2 tam bilet - indirim geçmez||{{ulaşım sembol|istanbul|M11}} {{ulaşım sembol|istanbul|Marmaray}}
|-
| H6 Yunus Emre - İstanbul Havalimanı || 2 tam bilet - indirim geçmez|| {{ulaşım sembol|istanbul|M11}}
|-
| H8 Hacıosman - İstanbul Havalimanı || 2 tam bilet - indirim geçmez|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|M11}}
|-
| 16S Sabiha Gökçen Havalimanı - Uzunçayır / Harem Peronlar || Standart || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|istanbul|Metrobüs}}
|-
| 122H Sabiha Gökçen Havalimanı - 4. Levent Metro|| bölgesel - 2. boğazgeç|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| 130H Deniz Harp Okulu - Sabiha Gökçen Havalimanı|| Standart || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| 132H Pendik / Pendik Yüksek Hızlı Tren - Sabiha Gökçen Havalimanı|| Standart || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| MR60 Pendik - Sabiha Gökçen Havalimanı|| Besleme - Tek bilet|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| E3 Sabiha Gökçen Havalimanı - 4.Levent|| 3 tam bilet - indirim geçmez|| {{ulaşım sembol|istanbul|M2}} {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| E10 Sabiha Gökçen Havalimanı - Kadıköy|| 2 tam bilet - indirim geçmez|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| SG1 Sabiha Gökçen Havalimanı - Kadıköy (HAVABÜS)|| 7 tam bilet - abonman ve indirim geçmez || {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}} {{ulaşım sembol|türkiye|yüksekhızlıtren}}
|-
| SG2 Sabiha Gökçen Havalimanı - Taksim (HAVABÜS)|| 11 tam bilet - abonman ve indirim geçmez||{{ulaşım sembol|istanbul|T2}} {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M10}}
|-
| UM73 Sabiha Gökçen Havalimanı - Necip Fazıl|| Besleme - Metro entegre - Tek bilet|| {{ulaşım sembol|istanbul|M4}} {{ulaşım sembol|istanbul|M5}} {{ulaşım sembol|istanbul|M10}}
|-
|}
== Metrobüs hatları ==
{| class="wikitable sortable" style="width: 100%;"
|-
! Hat ismi !! Sefer süresi
|-
| 34 Avcılar - Zincirlikuyu || 72 dakika
|-
| 34A Cevizlibağ - Kadıköy Söğütlüçeşme || 49 dakika
|-
| 34B Beylikdüzü - Avcılar || 24 dakika
|-
| 34BZ Beylikdüzü - Zincirlikuyu || 80 dakika
|-
| 34C Beylikdüzü - Cevizlibağ || 70 dakika
|-
| 34G Beylikdüzü - Kadıköy Söğütlüçeşme || 116 dakika
|-
| 34T Avcılar - Topkapı || 47 dakika
|-
| 34U Zincirlikuyu - Uzunçayır || 16 dakika
|-
| 34Z Zincirlikuyu - Kadıköy Söğütlüçeşme || 21 dakika
rsexkt6ffmjrp79q6tfrwbxfqq8cxxx
Kullanıcı:Brightt11/Oyver.js
2
5074
17860
17855
2026-10-24T16:47:17Z
Brightt11
1786
yorum simgesi eklendi
17860
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.1 beta.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.1 beta',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmi karşı', template: 'Kısmi karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original' }, requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
rx6wddjjnhi4hpbs6ng8v5celd4897j
17861
17860
2026-10-24T16:48:18Z
Brightt11
1786
Restored revision 17855 by [[Special:Contributions/Brightt11|Brightt11]] ([[User talk:Brightt11|talk]]) (TwinkleGlobal)
17861
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.0.1 beta',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmi karşı', template: 'Kısmi karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
rcxsqsnbx90vhh6lymn1p3cf9wi24m2
17864
17861
2026-10-24T17:05:58Z
Brightt11
1786
yorum simgesi eklendi
17864
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.1 beta.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.1 beta',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmi karşı', template: 'Kısmi karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
6m9b4kyvsaw3mmgn7nm57m7pabdhcm5
17872
17864
2026-10-24T17:14:27Z
Brightt11
1786
kısmi karşı -> kısmen karşı
17872
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.1.1 beta.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.1.1 beta',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmen karşı', template: 'Kısmen karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
9jxbyhjj4lhxc39725r1x8z6gihxub9
17877
17872
2026-10-24T19:12:46Z
Brightt11
1786
- fixed signature bug
17877
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.1.1 beta.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.2 beta',
signature: '~~' + '~~',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmen karşı', template: 'Kısmen karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' voteLine += ' ' + self.signature;';
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
bll6hopx56tgwg7wrf15p9x7vsrp98m
17878
17877
2026-10-24T19:14:18Z
Brightt11
1786
fix again
17878
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.1.1 beta.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.2 beta',
signature: '~~' + '~~',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmen karşı', template: 'Kısmen karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' [[Kullanıcı:Brightt11|Brightt11]] ([[Kullanıcı mesaj:Brightt11|mesaj]]) 23.25, 23 Ekim 2026 (UTC)';
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
rc504l7fbjh0yewruee2wxfg428w6i6
17881
17878
2026-10-24T19:18:18Z
Brightt11
1786
fixed signature bug. again.
17881
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.3 beta.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.3 beta',
signature: '~~' + '~~',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmen karşı', template: 'Kısmen karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
opuae1h61pty5kou9a167pi7ue6sjq7
17884
17881
2026-10-24T19:21:04Z
Brightt11
1786
version
17884
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.0 beta 3.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.0 beta 3',
signature: '~~' + '~~',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmen karşı', template: 'Kısmen karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
6e9f5qj0qobaf49goj4uogtv2oyc26t
17885
17884
2026-10-24T19:21:26Z
Brightt11
1786
17885
javascript
text/javascript
// Oyver - EasyVoteMeta (Author: Max) betiğinin yerelleştirilmiş versiyonu.
// Orijinal betik kaynağı/Original script source: https://meta.wikimedia.org/wiki/User:Max/EasyVoteMeta.js
// Bu betik, oylama/görüş bildirme sayfalarında bölüm başlıklarına "hızlı oy ver" bağlantısı ekler.
// sürüm: 1.0 beta 3.
// <nowiki>
$(() => {
'use strict';
const Oyver = {
version: '1.0 beta 3',
signature: '~~' + '~~',
config: {
messages: {
windowTitle: 'Oyver',
windowButton: 'Gönder',
cancelButton: 'İptal',
vote: 'Görüş belirtmek için oy seçin:',
comment: 'Yorum:',
signatureAutoAdd: 'İmzanız otomatik olarak eklenecektir.',
editSummaryLabel: 'Değişiklik özeti',
showPreview: 'Önizlemeyi göster',
hidePreview: 'Önizlemeyi gizle',
preferencesTitle: 'Tercihler',
preferencesIconSetLabel: 'Oy simgesi görünümü',
preferencesIconSetCodex: 'Codex simgeleri',
preferencesIconSetOnWiki: 'Wiki simgeleri',
preferencesFullContextLabel: 'Önizlemede daima tüm bölümü göster',
preferencesSave: 'Kaydet',
preferencesButtonLabel: 'Tercihler',
closeButtonLabel: 'Kapat',
toggleFullSectionLabel: 'Tüm bölüm önizlemesini açın/kapatın',
loadingPreviewLabel: 'Önizleme yükleniyor',
submitting: 'Gönderiliyor. Lütfen internet tarayıcınızı açık tutun.',
voteLinkText: 'hızlı oy ver',
editError: 'Hata: Bir hata oldu. Klavyenizden F5 tuşuna basarak sayfayı yenileyin ve tekrar deneyin',
confirmPossibleDouble: 'Bu başvuruda daha önce görüş yapmışsınız. Devam etmek istediğinizden emin misiniz? Lütfen önceki görüş(ler)inizin üstünü çizerek (<nowiki><s></s></nowiki> kullanarak) oyunuzu geri çekin.'
},
voteOptions: {
support: { label: 'Destek', template: 'Destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/9/94/Symbol_support_vote.svg' },
halfsupport: { label: 'Kısmi destek', template: 'Kısmi destek', icon: 'cdxIconCheck', group: 'support', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/8c/GA_candidate.svg' },
oppose: { label: 'Karşı', template: 'Karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/7/7f/Symbol_oppose_vote.svg' },
halfoppose: { label: 'Kısmen karşı', template: 'Kısmen karşı', icon: 'cdxIconClose', group: 'oppose', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/f/f5/BA_candidate.svg' },
neutral: { label: 'Tarafsız', template: 'Tarafsız', icon: 'cdxIconInfoFilled', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/8/89/Symbol_neutral_vote.svg' },
comment: { label: 'Yorum', template: 'Yorum', icon: 'cdxIconSpeechBubble', group: 'neutral', iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/d/df/Pictogram_voting_comment_%28orange%29.svg?utm_source=commons.wikimedia.org&utm_campaign=index&utm_content=original', requiresComment: true, skipDoubleCheck: true }
},
voteAliases: [],
groupOrder: ['support', 'oppose', 'neutral'],
groupHeaders: {
support: ['Destek', 'Evet'],
oppose: ['Karşı', 'Hayır'],
neutral: ['Tarafsız', 'Yorum']
},
iconNames: ['cdxIconCheck', 'cdxIconClose', 'cdxIconInfoFilled', 'cdxIconAlert', 'cdxIconSpeechBubble', 'cdxIconEye', 'cdxIconEyeClosed', 'cdxIconSettings'],
summfix: ' ([[Kullanıcı:Brightt11/Oyver.js|Oyver (beta)]] ile görüş belirtildi.)',
pageConfigs: {
'Vikigezgin:Kullanıcı hakları adaylıkları': {
type: 'auto',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: []
}
},
namespaceConfigs: {
8: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
},
828: {
type: 'direct',
headingSelector: 'div.mw-heading.mw-heading3',
skipPrefixes: [],
dbNames: []
}
}
},
icons: {},
prefsPrefix: 'userjs-oyver-',
prefsDefaults: {
iconSet: 'codex',
fullContextPreviewDefault: false
},
prefsCache: {},
prefs: {},
currentPageConfig: null,
init() {
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
this.currentPageConfig = this.config.pageConfigs[currentPage] ||
(this.config.namespaceConfigs || {})[mw.config.get('wgNamespaceNumber')];
if (!this.currentPageConfig) return;
const dbNames = this.currentPageConfig.dbNames;
if (dbNames && dbNames.length && !dbNames.includes(mw.config.get('wgDBname'))) return;
if (mw.user.isAnon()) return;
mw.loader.using(['vue', '@wikimedia/codex', 'mediawiki.util', 'mediawiki.api', 'mediawiki.user']).then((require) => {
this.Vue = require('vue');
this.Codex = require('@wikimedia/codex');
this.run();
});
},
async loadIcons() {
try {
const api = new mw.Api();
const data = await api.get({
action: 'query',
list: 'codexicons',
names: this.config.iconNames.join('|'),
formatversion: 2
});
this.icons = (data && data.query && data.query.codexicons) || {};
} catch (error) {
this.icons = {};
}
},
getPrefFullKey(key) {
return this.prefsPrefix + key;
},
loadPref(key) {
const fullKey = this.getPrefFullKey(key);
const fallback = this.prefsDefaults[key];
let value;
if (Object.prototype.hasOwnProperty.call(this.prefsCache, fullKey)) {
value = this.prefsCache[fullKey];
} else {
try {
value = window.localStorage ? window.localStorage.getItem(fullKey) : null;
} catch (error) {
value = null;
}
}
if (value !== null && value !== undefined) {
try {
return JSON.parse(value);
} catch (error) {
return fallback;
}
}
try {
const serverValue = mw.user.options.get(fullKey, JSON.stringify(fallback));
return JSON.parse(serverValue);
} catch (error) {
return fallback;
}
},
loadAllPrefs() {
const prefs = {};
Object.keys(this.prefsDefaults).forEach((key) => {
prefs[key] = this.loadPref(key);
});
return prefs;
},
async savePref(key, value) {
const fullKey = this.getPrefFullKey(key);
const fullValue = JSON.stringify(value);
this.prefsCache[fullKey] = fullValue;
try {
if (window.localStorage) window.localStorage.setItem(fullKey, fullValue);
} catch (error) { }
try {
const api = new mw.Api();
await api.postWithEditToken({
action: 'options',
optionname: fullKey,
optionvalue: fullValue
});
} catch (error) {
console.error('Oyver: Hata. Tercih kaydedilemedi.', key, error);
}
},
async savePrefs(newPrefs) {
const keys = Object.keys(newPrefs);
for (const key of keys) {
await this.savePref(key, newPrefs[key]);
}
},
async run() {
this.addStyle();
this.prefs = this.loadAllPrefs();
await this.loadIcons();
const pageConfig = this.currentPageConfig;
const skipPrefixes = (pageConfig.skipPrefixes || []).map((p) => p.toLocaleLowerCase('tr'));
$(pageConfig.headingSelector || 'div.mw-heading.mw-heading3').each((_, heading) => {
const $heading = $(heading);
const editLinks = $heading.find('.mw-editsection');
const headingId = $heading.find('h1,h2,h3,h4,h5,h6').first().attr('id');
if (!headingId) return;
const sectionTitle = headingId.replace(/_/g, ' ');
const normalizedTitle = sectionTitle.toLocaleLowerCase('tr');
if (skipPrefixes.some((prefix) => normalizedTitle.startsWith(prefix))) return;
if (pageConfig.type === 'direct') {
this.handleDirectPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'transcluded') {
this.handleTranscludedPage(editLinks, sectionTitle, $heading);
} else if (pageConfig.type === 'auto') {
this.handleAutoPage(editLinks, sectionTitle, $heading);
}
});
},
handleAutoPage(editLinks, sectionTitle, $heading) {
const info = this.getTargetPageInfo(editLinks);
if (!info) return;
const currentPage = mw.config.get('wgPageName').replace(/_/g, ' ');
if (info.targetPage === currentPage && /^\d+$/.test(info.sectionId)) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum: parseInt(info.sectionId, 10) }, $heading);
} else {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, info), $heading);
}
},
handleDirectPage(editLinks, sectionTitle, $heading) {
const sectionNum = this.getSectionNumber(editLinks);
if (sectionNum !== -1) {
this.addVoteLink(editLinks, sectionTitle, { type: 'direct', sectionNum }, $heading);
}
},
handleTranscludedPage(editLinks, sectionTitle, $heading) {
const targetPageInfo = this.getTargetPageInfo(editLinks);
if (targetPageInfo && targetPageInfo.targetPage && targetPageInfo.sectionId) {
this.addVoteLink(editLinks, sectionTitle, Object.assign({ type: 'transcluded' }, targetPageInfo), $heading);
}
},
addStyle() {
mw.util.addCSS(`
.script-Oyver-link {
color: var(--color-progressive, #36c);
text-decoration: none;
font-weight: bold;
}
.script-Oyver-link:hover {
text-decoration: underline;
}
.script-Oyver-disabled {
color: var(--color-disabled, #a2a9b1) !important;
pointer-events: none;
}
.script-Oyver-divider {
border: none;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
margin: 8px 0 4px;
}
.script-Oyver-panel {
border: 1px solid var(--border-color-base, #a2a9b1);
background: var(--background-color-base, #fff);
padding: 16px;
margin: 8px 0 16px;
}
.script-Oyver-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.script-Oyver-panel-title {
font-weight: bold;
font-size: 15px;
}
.script-Oyver-version {
font-size: 0.7em;
font-weight: normal;
color: var(--color-subtle, #54595d);
vertical-align: middle;
margin-left: 2px;
}
.script-Oyver-header-actions {
display: flex;
gap: 4px;
}
.script-Oyver-panel-body p:first-child {
margin-top: 0;
}
.script-Oyver-option {
margin: 8px 0;
}
.script-Oyver-option .cdx-icon {
margin-right: 4px;
}
.script-Oyver-onwiki-icon {
margin-right: 4px;
vertical-align: middle;
}
.script-Oyver-field {
margin-top: 14px;
}
.script-Oyver-signature-note {
font-style: italic;
color: var(--color-subtle, #54595d);
font-size: 0.9em;
margin-top: 8px;
}
.script-Oyver-status {
margin-top: 12px;
}
.script-Oyver-buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.script-Oyver-preview-wrapper {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-color-subtle, #eaecf0);
}
.script-Oyver-preview-toolbar {
display: flex;
justify-content: flex-end;
}
.script-Oyver-preview {
margin-top: 0;
}
.script-Oyver-preview-content {
font-size: 0.95em;
line-height: 1.6;
}
.script-Oyver-preview-loading {
display: flex;
align-items: center;
gap: 8px;
color: var(--color-subtle, #54595d);
font-size: 0.88em;
}
.script-Oyver-prefs {
border: 1px solid var(--border-color-subtle, #eaecf0);
padding: 12px;
}
.script-Oyver-prefs-title {
font-weight: bold;
margin: 0 0 8px;
}
`);
},
getSectionNumber(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
const sectionMatch = editSectionUrl && editSectionUrl.match(/[?&]section=(\d+)(?:&|$)/);
return sectionMatch ? parseInt(sectionMatch[1], 10) : -1;
},
getTargetPageInfo(editLinks) {
const editSectionUrl = editLinks.find('a:first').attr('href');
if (!editSectionUrl) return null;
const titleMatch = editSectionUrl.match(/[?&]title=([^&]+)/);
const sectionMatch = editSectionUrl.match(/[?&]section=([^&]+)/);
if (!titleMatch || !sectionMatch) return null;
return {
targetPage: decodeURIComponent(titleMatch[1]).replace(/_/g, ' '),
sectionId: sectionMatch[1]
};
},
extractContent(apiData) {
const pages = apiData && apiData.query && apiData.query.pages;
if (!pages || !pages[0] || !pages[0].revisions || !pages[0].revisions[0]) return null;
return pages[0].revisions[0].content;
},
sanitizeSectionTitle(rawTitle) {
if (!rawTitle) return '';
const emojiPattern = /(\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u{1F1E6}-\u{1F1FF}]|\u{FE0F}|\u{200D})/gu;
let text = rawTitle.replace(emojiPattern, '');
let cutIndex = -1;
for (let i = 0; i < text.length; i++) {
if (text[i] === '(') {
cutIndex = i;
break;
}
if (text[i] === '[') {
if (text[i + 1] === '[') {
i++;
continue;
}
cutIndex = i;
break;
}
}
if (cutIndex !== -1) {
text = text.substring(0, cutIndex);
}
return text.replace(/\s+/g, ' ').trim();
},
detectGroupHeaderType(line) {
const match = line.match(/^;\s*(\S.*)$/);
if (!match) return null;
const text = match[1].toLocaleLowerCase('tr');
for (const key of this.config.groupOrder) {
const words = this.config.groupHeaders[key] || [];
for (const word of words) {
const w = word.toLocaleLowerCase('tr');
if (text.startsWith(w) && !/^\p{L}/u.test(text.slice(w.length))) {
return key;
}
}
}
return null;
},
findGroupHeaders(lines) {
return lines.reduce((acc, line, idx) => {
const type = this.detectGroupHeaderType(line);
if (type) acc.push({ type, index: idx });
return acc;
}, []);
},
findGroupBlockEnd(lines, headerIdx) {
for (let i = headerIdx + 1; i < lines.length; i++) {
if (this.detectGroupHeaderType(lines[i])) return i;
}
return lines.length;
},
getBlockBulletChar(lines, headerIdx, blockEnd) {
for (let i = headerIdx + 1; i < blockEnd; i++) {
const match = lines[i].match(/^\s*([#*:]+)/);
if (match) return match[1];
}
return '*';
},
getGroupHeaderText(group) {
const words = this.config.groupHeaders[group];
return (words && words[0]) || group;
},
buildGroupedVoteText(sectionText, group, voteLine) {
const lines = sectionText.split('\n');
const headers = this.findGroupHeaders(lines);
const existing = headers.find((h) => h.type === group);
const headerLine = ';' + this.getGroupHeaderText(group);
if (existing) {
const blockEnd = this.findGroupBlockEnd(lines, existing.index);
let insertIdx = blockEnd;
while (insertIdx - 1 > existing.index && lines[insertIdx - 1].trim() === '') insertIdx--;
lines.splice(insertIdx, 0, voteLine);
return lines.join('\n');
}
const order = this.config.groupOrder;
const orderIdx = order.indexOf(group);
for (let o = orderIdx + 1; o < order.length; o++) {
const laterHeader = headers.find((h) => h.type === order[o]);
if (laterHeader) {
lines.splice(laterHeader.index, 0, headerLine, voteLine, '');
return lines.join('\n');
}
}
for (let o = orderIdx - 1; o >= 0; o--) {
const earlierHeader = headers.find((h) => h.type === order[o]);
if (earlierHeader) {
const blockEnd = this.findGroupBlockEnd(lines, earlierHeader.index);
lines.splice(blockEnd, 0, '', headerLine, voteLine);
return lines.join('\n');
}
}
let lastNonBlank = lines.length - 1;
while (lastNonBlank >= 0 && lines[lastNonBlank].trim() === '') lastNonBlank--;
lines.splice(lastNonBlank + 1, 0, '', headerLine, voteLine);
return lines.join('\n');
},
hasExistingVote(sectionText, currentUser) {
const templates = Object.values(this.config.voteOptions).filter((opt) => !opt.skipDoubleCheck).map((opt) => opt.template);
const aliases = this.config.voteAliases || [];
const allNames = [...templates, ...aliases].map((name) => mw.util.escapeRegExp(name));
const escapedUser = mw.util.escapeRegExp(currentUser);
const pattern = new RegExp('\\{\\{(?:' + allNames.join('|') + ')\\}\\}[^\\n~]{0,300}?' + escapedUser, 'i');
return pattern.test(sectionText);
},
addVoteLink(editLinks, sectionTitle, pageInfo, $heading) {
const uniqueId = 'script-Oyver-launch-' + Math.random().toString(36).slice(2, 11);
const mountId = 'script-Oyver-mount-' + uniqueId;
const voteLink = $('<a>')
.attr('id', uniqueId)
.addClass('script-Oyver-link')
.text(this.config.messages.voteLinkText)
.attr('href', '#')
.click((event) => {
event.preventDefault();
if (!voteLink.hasClass('script-Oyver-disabled')) {
voteLink.addClass('script-Oyver-disabled');
if (!$('#' + mountId).length) {
$heading.after(
$('<div>').attr('id', mountId),
$('<hr>').addClass('script-Oyver-divider')
);
}
this.showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId);
}
});
editLinks.children().last().before(' | ', voteLink);
},
getPreviewComponent() {
const loadingLabel = this.config.messages.loadingPreviewLabel;
return {
components: {
CdxProgressBar: this.Codex.CdxProgressBar
},
props: { wikitext: { type: String, default: '' } },
data() {
return { previewHtml: '', haveHtml: false, loadingLabel };
},
methods: {
loadPreview(wikitextToPreview) {
new mw.Api().get({
action: 'parse',
formatversion: 2,
title: mw.config.get('wgPageName'),
text: wikitextToPreview,
prop: 'text',
pst: true,
disablelimitreport: true,
disableeditsection: true,
sectionpreview: true
}).then((res) => {
if (res && res.parse && res.parse.text) {
this.previewHtml = res.parse.text;
this.haveHtml = true;
}
});
}
},
watch: {
wikitext: {
immediate: true,
handler(newValue) {
this.previewHtml = '';
this.haveHtml = false;
this.loadPreview(newValue);
}
}
},
template: `
<div class="script-Oyver-preview">
<div v-if="!haveHtml" class="script-Oyver-preview-loading">
<cdx-progress-bar inline :aria-label="loadingLabel"></cdx-progress-bar>
</div>
<div v-else class="script-Oyver-preview-content" v-html="previewHtml"></div>
</div>
`
};
},
showPanel(sectionTitle, pageInfo, $heading, uniqueId, mountId) {
const self = this;
const rawLiveSectionTitle = $heading.contents().not($heading.find('.mw-editsection')).text().trim() || sectionTitle;
const liveSectionTitle = self.sanitizeSectionTitle(rawLiveSectionTitle);
const vueAppInstance = self.Vue.createMwApp({
components: {
CdxRadio: self.Codex.CdxRadio,
CdxCheckbox: self.Codex.CdxCheckbox,
CdxTextArea: self.Codex.CdxTextArea,
CdxTextInput: self.Codex.CdxTextInput,
CdxField: self.Codex.CdxField,
CdxAccordion: self.Codex.CdxAccordion,
CdxMessage: self.Codex.CdxMessage,
CdxButton: self.Codex.CdxButton,
CdxIcon: self.Codex.CdxIcon,
previewRenderer: self.getPreviewComponent()
},
data() {
return {
version: self.version,
messages: self.config.messages,
sectionTitle: liveSectionTitle,
uniqueId,
voteOptions: Object.entries(self.config.voteOptions).map(([value, opt]) => ({
value,
label: opt.label,
group: opt.group,
icon: self.icons[opt.icon] || null,
iconUrl: opt.iconUrl,
requiresComment: !!opt.requiresComment
})),
selectedVote: null,
comment: '',
showSummary: false,
editSummaryInput: '/* ' + liveSectionTitle + ' */ ',
summaryEdited: false,
showPreview: false,
submitting: false,
submitError: '',
showContextPreview: false,
contextPreviewWikitext: '',
contextPreviewLoading: false,
contextPreviewDebounce: null,
showPreferences: false,
iconSetPref: self.prefs.iconSet,
prefsIconSet: self.prefs.iconSet,
prefsFullContext: self.prefs.fullContextPreviewDefault,
savingPrefs: false,
checkIcon: self.icons.cdxIconCheck || null,
closeIcon: self.icons.cdxIconClose || null,
eyeIcon: self.icons.cdxIconEye || null,
eyeClosedIcon: self.icons.cdxIconEyeClosed || null,
settingsIcon: self.icons.cdxIconSettings || null
};
},
computed: {
panelTitle() {
return this.messages.windowTitle + ': ' + this.sectionTitle;
},
radioName() {
return 'script-Oyver-vote-' + this.uniqueId;
},
prefsIconSetName() {
return 'script-Oyver-prefs-iconset-' + this.uniqueId;
},
selectedOption() {
return this.voteOptions.find((opt) => opt.value === this.selectedVote) || null;
},
defaultSummary() {
const base = '/* ' + this.sectionTitle + ' */ ';
return this.selectedOption ? base + this.selectedOption.label : base;
},
canSubmit() {
if (this.submitting || !this.selectedVote) return false;
if (this.selectedOption && this.selectedOption.requiresComment && !this.comment.trim()) return false;
return true;
},
previewToggleIcon() {
return this.showPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewToggleLabel() {
return this.showPreview ? this.messages.hidePreview : this.messages.showPreview;
},
contextToggleIcon() {
return this.showContextPreview ? this.eyeClosedIcon : this.eyeIcon;
},
previewWikitext() {
if (!this.selectedOption) return '';
const templateName = self.config.voteOptions[this.selectedVote].template;
const trimmedComment = this.comment.trim();
let voteLine = '* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return voteLine;
}
},
watch: {
selectedVote() {
if (!this.summaryEdited) {
this.editSummaryInput = this.defaultSummary;
}
if (this.showContextPreview) {
this.refreshContextPreview();
}
},
comment() {
if (!this.showContextPreview) return;
clearTimeout(this.contextPreviewDebounce);
this.contextPreviewDebounce = setTimeout(() => {
this.refreshContextPreview();
}, 400);
}
},
methods: {
cancelPanel() {
if (this.submitting) return;
vueAppInstance.unmount();
$('#' + mountId).empty();
$('#' + uniqueId).removeClass('script-Oyver-disabled');
},
togglePreferences() {
if (this.submitting) return;
this.prefsIconSet = self.prefs.iconSet;
this.prefsFullContext = self.prefs.fullContextPreviewDefault;
this.showPreferences = !this.showPreferences;
},
async savePreferences() {
this.savingPrefs = true;
const newPrefs = {
iconSet: this.prefsIconSet,
fullContextPreviewDefault: this.prefsFullContext
};
await self.savePrefs(newPrefs);
self.prefs = Object.assign({}, self.prefs, newPrefs);
this.iconSetPref = self.prefs.iconSet;
this.savingPrefs = false;
this.showPreferences = false;
},
async togglePreview() {
if (this.showPreview) {
this.showPreview = false;
return;
}
if (self.prefs.fullContextPreviewDefault && !this.showContextPreview) {
await this.toggleContextPreview();
}
this.showPreview = true;
},
async toggleContextPreview() {
if (this.showContextPreview) {
this.showContextPreview = false;
return;
}
if (!this.selectedOption) return;
await this.refreshContextPreview();
this.showContextPreview = true;
},
buildQueryParams() {
const queryParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2
};
if (pageInfo.type === 'direct') {
queryParams.titles = mw.config.get('wgPageName');
queryParams.rvsection = pageInfo.sectionNum;
} else {
queryParams.titles = pageInfo.targetPage;
queryParams.rvsection = pageInfo.sectionId;
}
return queryParams;
},
buildNewSectionText(sectionText) {
const templateName = self.config.voteOptions[this.selectedVote].template;
const group = self.config.voteOptions[this.selectedVote].group;
const trimmedComment = this.comment.trim();
const headers = self.findGroupHeaders(sectionText.split('\n'));
if (headers.length) {
const lines = sectionText.split('\n');
const existingHeader = headers.find((h) => h.type === group);
const blockEnd = existingHeader ? self.findGroupBlockEnd(lines, existingHeader.index) : -1;
const bulletChar = existingHeader ? self.getBlockBulletChar(lines, existingHeader.index, blockEnd) : '*';
let voteLine = bulletChar + ' {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return { text: self.buildGroupedVoteText(sectionText, group, voteLine) };
}
let voteLine = '\n* {{' + templateName + '}}';
if (trimmedComment) voteLine += ' ' + trimmedComment;
voteLine += ' ' + self.signature;
return { appendtext: voteLine, previewText: sectionText + voteLine };
},
async refreshContextPreview() {
if (!this.selectedOption) return;
this.contextPreviewLoading = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const built = this.buildNewSectionText(sectionText);
this.contextPreviewWikitext = built.text !== undefined ? built.text : built.previewText;
} catch (error) {
console.error('Oyver: bölüm önizlemesi başarısız', error);
} finally {
this.contextPreviewLoading = false;
}
},
async doVote() {
this.submitError = '';
this.submitting = true;
try {
const api = new mw.Api();
const res = await api.get(this.buildQueryParams());
const sectionText = self.extractContent(res);
if (sectionText === null) throw new Error('Bölüm içeriği alınamadı');
const currentUser = mw.config.get('wgUserName');
if (self.hasExistingVote(sectionText, currentUser)) {
if (!confirm(this.messages.confirmPossibleDouble)) {
this.submitting = false;
return;
}
}
const summaryBase = this.editSummaryInput.trim() || this.defaultSummary;
const editSummary = summaryBase + self.config.summfix;
const editParams = {
action: 'edit',
summary: editSummary,
token: mw.user.tokens.get('csrfToken')
};
if (pageInfo.type === 'direct') {
editParams.title = mw.config.get('wgPageName');
editParams.section = pageInfo.sectionNum;
} else {
editParams.title = pageInfo.targetPage;
editParams.section = pageInfo.sectionId;
}
const built = this.buildNewSectionText(sectionText);
if (built.text !== undefined) {
editParams.text = built.text;
} else {
editParams.appendtext = built.appendtext;
}
await api.postWithEditToken(editParams);
setTimeout(() => {
window.location.reload();
}, 1200);
} catch (error) {
console.error('Oyver: gönderim başarısız', error);
this.submitError = this.messages.editError;
this.submitting = false;
}
}
},
template: `
<div class="script-Oyver-panel">
<div class="script-Oyver-panel-header">
<span class="script-Oyver-panel-title">
{{ panelTitle }}
<span class="script-Oyver-version">v{{ version }}</span>
</span>
<div class="script-Oyver-header-actions">
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.preferencesButtonLabel" :title="messages.preferencesButtonLabel" @click="togglePreferences">
<cdx-icon v-if="settingsIcon" :icon="settingsIcon"></cdx-icon>
</cdx-button>
<cdx-button weight="quiet" :disabled="submitting" :aria-label="messages.closeButtonLabel" :title="messages.closeButtonLabel" @click="cancelPanel">
<cdx-icon v-if="closeIcon" :icon="closeIcon"></cdx-icon>
</cdx-button>
</div>
</div>
<div v-if="showPreferences" class="script-Oyver-panel-body">
<div class="script-Oyver-prefs">
<p class="script-Oyver-prefs-title">{{ messages.preferencesTitle }}</p>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.preferencesIconSetLabel }}</template>
<cdx-radio v-model="prefsIconSet" input-value="codex" :name="prefsIconSetName">
{{ messages.preferencesIconSetCodex }}
</cdx-radio>
<cdx-radio v-model="prefsIconSet" input-value="onwiki" :name="prefsIconSetName">
{{ messages.preferencesIconSetOnWiki }}
</cdx-radio>
</cdx-field>
<cdx-checkbox v-model="prefsFullContext" class="script-Oyver-field">
{{ messages.preferencesFullContextLabel }}
</cdx-checkbox>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="savingPrefs" @click="savePreferences">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.preferencesSave }}
</cdx-button>
<cdx-button :disabled="savingPrefs" @click="showPreferences = false">
{{ messages.cancelButton }}
</cdx-button>
</div>
</div>
</div>
<div v-else class="script-Oyver-panel-body">
<p>{{ messages.vote }}</p>
<div v-for="option in voteOptions" :key="option.value" class="script-Oyver-option">
<cdx-radio
v-model="selectedVote"
:input-value="option.value"
:name="radioName"
:disabled="submitting"
>
<cdx-icon v-if="iconSetPref === 'codex' && option.icon" :icon="option.icon"></cdx-icon>
<img
v-else-if="iconSetPref === 'onwiki' && option.iconUrl"
:src="option.iconUrl"
width="20"
height="20"
alt=""
class="script-Oyver-onwiki-icon"
>
{{ option.label }}
</cdx-radio>
</div>
<cdx-field class="script-Oyver-field">
<template #label>{{ messages.comment }}</template>
<cdx-text-area v-model="comment" :rows="3" :disabled="submitting"></cdx-text-area>
</cdx-field>
<p class="script-Oyver-signature-note">{{ messages.signatureAutoAdd }}</p>
<cdx-accordion v-model="showSummary" class="script-Oyver-field">
<template #title>{{ messages.editSummaryLabel }}</template>
<cdx-text-input
v-model="editSummaryInput"
:disabled="submitting"
@input="summaryEdited = true"
></cdx-text-input>
</cdx-accordion>
<cdx-message v-if="submitError" type="error" :allow-user-dismiss="false" class="script-Oyver-status">
{{ submitError }}
</cdx-message>
<cdx-message v-if="submitting" type="notice" :allow-user-dismiss="false" class="script-Oyver-status">
{{ messages.submitting }}
</cdx-message>
<div class="script-Oyver-buttons">
<cdx-button weight="primary" action="progressive" :disabled="!canSubmit" @click="doVote">
<cdx-icon v-if="checkIcon" :icon="checkIcon"></cdx-icon>
{{ messages.windowButton }}
</cdx-button>
<cdx-button :disabled="!selectedVote || submitting" @click="togglePreview">
<cdx-icon v-if="previewToggleIcon" :icon="previewToggleIcon"></cdx-icon>
{{ previewToggleLabel }}
</cdx-button>
<cdx-button :disabled="submitting" @click="cancelPanel">
{{ messages.cancelButton }}
</cdx-button>
</div>
<div v-if="showPreview && selectedVote" class="script-Oyver-preview-wrapper">
<div class="script-Oyver-preview-toolbar">
<cdx-button
weight="quiet"
:disabled="contextPreviewLoading"
:aria-label="messages.toggleFullSectionLabel"
:title="messages.toggleFullSectionLabel"
@click="toggleContextPreview"
>
<cdx-icon v-if="contextToggleIcon" :icon="contextToggleIcon"></cdx-icon>
</cdx-button>
</div>
<preview-renderer :wikitext="showContextPreview ? contextPreviewWikitext : previewWikitext"></preview-renderer>
</div>
</div>
</div>
`
});
vueAppInstance.mount('#' + mountId);
}
};
Oyver.init();
});
// </nowiki>
99au7bx31m9ubfagt91ad70qtid6c2k
Şablon:İnaktiflik politikası uyarı
10
5090
17859
2026-10-24T16:35:15Z
Brightt11
1786
+
17859
wikitext
text/x-wiki
{{çikutu|metin=Wikimedia Metawiki'de geçerli olan küresel politika gereğince arayüz yöneticiliği, hizmetlilik ve bürokratlık hakları bulunan kullanıcının 2 yıl inaktif kalması durumunda bu haklar geri alınır. Ayrıca geçici görev gören kullanıcılar süre bitiminden 1 hafta önce mesaj sayfalarında görev süresinin dolacağı ile ilgili bir bildirim alacaktır. Bu süre zarfında herhangi bir görev yenileme başvurusu yapılmaması durumunda kullanıcı hakları ikinci bir bildiri olmaksızın geri alınır. Kullanıcı haklarınızı korumak ve görevinize devam etmek istiyorsanız, geçici görev süresinin bitiminden 1 ay önce görev yenileme başvurusu yapmalısınız.}}
d0kiyermg1rdndbba8114pth7mtuxr6
Şablon:Kısmi destek
10
5091
17870
2026-10-24T17:12:56Z
Brightt11
1786
+
17870
wikitext
text/x-wiki
[[Dosya:GA candidate.svg|15pik|Kısmî destek|link=şablon:Kısmî destek]] '''{{{1|Kısmî destek}}}'''<noinclude>
[[Kategori:Resimli yorum şablonları]]
</noinclude>
bmilfvkwecwo2p7271d7uvu34cg3ro8
Şablon:Kısmen karşı
10
5092
17871
2026-10-24T17:13:03Z
Brightt11
1786
+
17871
wikitext
text/x-wiki
[[Dosya:BA candidate.svg|15pik|Kısmen karşı|link=şablon:Kısmen karşı]] '''{{{1|Kısmen karşı}}}'''<noinclude>
[[Kategori:Resimli yorum şablonları]]
</noinclude>
33vzomj4vx5bt3pcqcnh94bpoyytqtk