Yeniden herkese merhaba. 🙂 Bu başlıkta, JavaScript kullanarak basit bir BBCode editörü nasıl yapılır bunu anlatıyor olacağım. Eğer sizde kullanmak isterseniz, projenize göre eklemeler ve özelleştirmeler yapabilirsiniz.
NOT: Bu yazıda olup bitenleri tam olarak anlayabilmeniz için temel seviye HTML, orta seviye CSS ve JavaScript bilgisine ihtiyacınız olacaktır.
Öyleyse HTML kodlarımız ile başlayalım.
<div id="container">
<div id="form">
<div id="message-box">
<div id="top">
<div class="option" id="bb--bold" title="Bold">
<img src="https://svgur.com/i/SzK.svg" alt="Bold" class="top-bar--icon" ondragstart="javascript:return false;">
</div>
<div class="option" id="bb--italic" title="Italic">
<img src="https://svgur.com/i/T09.svg" alt="Italic" class="top-bar--icon" ondragstart="javascript:return false;">
</div>
<div class="option" id="bb--ul" title="Unordered List">
<img src="https://svgur.com/i/Syu.svg" alt="UL" class="top-bar--icon" ondragstart="javascript:return false;">
</div>
<div class="option" id="bb--ol" title="Ordered List">
<img src="https://svgur.com/i/Syv.svg" alt="OL" class="top-bar--icon" ondragstart="javascript:return false;">
</div>
<div class="option" id="bb--link" title="Link">
<img src="https://svgur.com/i/T0A.svg" alt="Link" class="top-bar--icon" ondragstart="javascript:return false;">
</div>
<div class="option" id="bb--align" title="Text Align">
<img src="https://svgur.com/i/Sxu.svg" alt="Align" class="top-bar--icon" ondragstart="javascript:return false;">
<ul class="dropdown-option vertical">
<li class="align-item" id="align-right" title="Align Right">Right</li>
<li class="align-item" id="align-center" title="Align Center">Center</li>
<li class="align-item" id="align-left" title="Align Left">Left</li>
</ul>
</div>
<div class="option" id="bb--emojis" title="Emojis">
<img src="https://svgur.com/i/SzW.svg" alt="Emojis" class="top-bar--icon" ondragstart="javascript:return false;">
<ul class="dropdown-option">
<li>
<img title="" src="https://twemoji.maxcdn.com/2/72x72/1f642.png" class="emoji-icon--dropdown" id="e-1" ondragstart="javascript:return false;">
</li>
<li>
<img title="" src="https://twemoji.maxcdn.com/2/72x72/1f604.png" class="emoji-icon--dropdown" id="e-2" ondragstart="javascript:return false;">
</li>
<li>
<img title="" src="https://twemoji.maxcdn.com/2/72x72/1f923.png" class="emoji-icon--dropdown" id="e-3" ondragstart="javascript:return false;">
</li>
<li>
<img title="" src="https://twemoji.maxcdn.com/2/72x72/1f643.png" class="emoji-icon--dropdown" id="e-4" ondragstart="javascript:return false;">
</li>
<li>
<img title="" src="https://twemoji.maxcdn.com/2/72x72/1f60d.png" class="emoji-icon--dropdown" id="e-5" ondragstart="javascript:return false;">
</li>
</ul>
</div>
<div class="option" id="bb--new-line" title="New Line">
<img src="https://svgur.com/i/Sz0.svg" alt="New Line" class="top-bar--icon" ondragstart="javascript:return false;">
</div>
</div>
<div id="textarea-box">
<textarea id="textarea" cols="30" rows="13"></textarea>
</div>
<button id="submit">Submit</button>
</div>
</div>
<div id="output">
</div>
</div>
Şimdi bu satırları açıklamak gerekirse; en başta ID'si container
olan taşıyıcı bir element oluşturuyoruz ve onun altına da 2 adet yeni elementler oluşturuyoruz: #form
ve #output
. #form
, bizim editörümüzün bulunacağı taşıyıcı element, #output
ise sonucumuzun görüneceği element. #form
elementinin içine ID'si message-box
olan bir element oluşturuyoruz. Bu elementin içine BBCode'larımıza hızlıca erişeceğimiz kısayol butonlarımızın bulunacağı #top
elementini, onun altına da yazıları yazacağımız alanın bulunacağı element olan #textarea-box
'ı ve onun da altına yazdığımız yazının sonuçlarını #output
elementinde göstermek için basacağımız #submit
butonu bulunuyor. Eğer HTML bilginiz varsa yazılanları daha iyi anlayacaksınızdır. #top
elementinin altında çok fazla element olduğu için tek tek anlatmayacağım.
Şimdi CSS kodlarımıza geçebiliriz.
/*- Inter -*/
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
/*- Fira Mono -*/
@import url('https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500;700&display=swap');
* {
margin: 0;
padding: 0;
outline: none;
box-sizing: border-box;
}
::selection {
background: rgba(50, 147, 237, 0.4);
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: #e6e6e6;
}
::-webkit-scrollbar-thumb {
background: #229ce3;
border-radius: 100ch;
cursor: pointer;
}
body {
font-family: "Inter", sans-serif;
overflow: auto;
}
Bu kodlar ile 2 adet font ailesini CSS dosyamıza dahil ediyor; bütün elementlerin margin
ve padding
değerlerini sıfırlayıp outline
'ı kaldırıyoruz. Sonrasında metin seçimi yapıldığında tarayıcının varsayılan arkaplan rengini görmek yerine kendi arkaplan rengimizi tanıtıyoruz. Ardından, tarayıcının varsayılan scrollbar'ını kendimiz özelleştiriyoruz ve <body>
etiketi arasında olan bütün elementlerin yazı tipini "Inter" yapıp, herhangi bir taşma durumunda otomatik olarak tepki verilmesi için overflow
özelliğine auto
değerini veriyoruz.
#container {
width: 100%;
height: 100vh;
min-width: max-content;
background: efefef;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
Bu bloğumuzda; ID'si container
olan elementimizin genişlik, yükseklik, arkaplan ve görüntüleme gibi özelliklerini değiştiriyoruz.
#form {
width: 50%;
height: max-content;
background: #0ff;
position: relative;
border-radius: 15px;
min-width: 700px !important;
}
Bu blokta; ID'si form
olan 2. taşıyıcı elementimizin genişlik, yükseklik, konumlandırma ve kenar ovalliği gibi değerlerini ayarlıyoruz.
.option .top-bar--icon {
width: 25px;
height: auto;
}
Bu blokta; üstteki HTML kodumuzda da gördüğünüz, ID'si top
olan taşıyıcı elementimizin içerisinde bulunan ve bizim BBCode'ları eklememizi kolaylaştıracak olan kısayollarımızın içindeki resimlerin boyutunu ayarlıyoruz.
textarea#textarea {
width: 100%;
height: 100%;
border-bottom-right-radius: 15px;
border-bottom-left-radius: 15px;
resize: none;
border-top-right-radius: 0;
border-top-left-radius: 0;
transition: box-shadow 0.2s;
font-family: "Fira Mono", monospace;
padding: 10px;
font-size: 16px;
border: 1px solid #a8a8a8;
}
Bu blokta ise; ID'si textarea
olan <textarea>
etiketimizin genişlik, yükseklik, boyutlandırma, kenar ovalliği, yazı tipi, içten öteleme, kenar çizgisi ve dönüşüm özelliklerini ayarlıyoruz.
textarea#textarea:focus {
box-shadow: 0px 0px 0px 5px rgba(50, 147, 237, 0.4);
}
Bu blokta ise; ID'si textarea
olan <textarea>
etiketimize odaklanıldığında açık mavi renkli bir kenarlık gibi görünecek olan gölgemizi oluşturuyoruz.
#form #top {
width: 100%;
height: max-content;
background: linear-gradient(90deg, #11a2f0, #0935ad);
display: flex;
flex-direction: row;
justify-content: space-evenly;
border-top-right-radius: 15px;
border-top-left-radius: 15px;
padding: 20px 0px;
}
Bu bölümde; #form
elementimizin içindeki #top
elementinin genişlik, yükseklik, arkaplan rengi, görüntüleme ve içten öteleme gibi özelliklerine istediğimiz değerleri veriyoruz.
#top .option {
padding: 10px;
border-radius: 10px;
margin-left: 10px;
background: #fff;
cursor: pointer;
transition: border 0.2s;
display: flex;
justify-content: center;
align-items: center;
transition: transform 0.2s;
}
Bu blokta; #top
elementimizin içinde bulunan ve class'ı option
olan bütün elementlerimize ortak özellikleri veriyoruz.
#top .option:first-child {
margin-left: 0;
}
Bu blokta; #top
elementinin içinde yer alan ve class'ı option
olan ilk elementimizin soldan öteleme değerini sıfırlıyoruz ki, orantısızlık olmasın.
#top .option:hover {
transform: scale(1.1);
}
#top .option:active {
transform: scale(0.9);
}
Burada; #top
elementimizin içerisindeki option
class'ına sahip bütün elementlerin üzerine gelindiğinde ve tıklandığında dönüşüm değerleriyle oynuyoruz.
#output {
min-width: 700px;
padding: 15px;
font-size: 17px;
border: 1px solid #a8a8a8;
border-radius: 15px;
margin-top: 4px;
}
Bu blokta; ID'si output
olan elementimize gereken görünüş özelliklerini veriyoruz.
#output ul, #output ol {
padding-left: 15px;
}
Bu blokta; BBCode ile oluşturulacak olan <ul>
ve <ol>
etiketine sahip olan liste elementlerinin solunda bulunan liste simgelerinin, #output
elementinin sol kenarı ile olan bağını kesmek için sol taraftan içten öteleme veriyoruz. Ne dediğimi tam olarak anlamak için bu kodları yorum satırına alıp aradaki farkı gözlemleyebilirsiniz.
button#submit {
width: 100%;
height: auto;
font-size: 20px;
border-radius: 15px;
color: #fff;
background: linear-gradient(90deg, #11a2f0, #0935ad);
border: none;
padding: 15px;
cursor: pointer;
transition: 0.2s;
position: relative;
font-family: "Inter", sans-serif;
font-weight: 900;
box-shadow: 0px 0px 0px 0px rgba(24, 116, 242, 0.6);
}
button#submit:focus {
box-shadow: 0px 0px 0px 5px rgba(24, 116, 242, 0.6);
}
Bu blokta; ID'si submit
olan butonumuza istediğimiz görünüş özelliklerini veriyori ve butona odaklanıldığında kenarında bir kalın bir çizgiymiş gibi görünecek olan gölgeyi ortaya çıkarıyoruz.
ul.dropdown-option {
cursor: default;
width: max-content;
position: absolute;
list-style-type: none;
display: flex;
justify-content: center;
flex-direction: row;
align-items: center;
background: #fff;
padding: 15px;
border-radius: 15px;
box-shadow: 0px 0px 10px rgba(92, 92, 92, 0.5);
opacity: 0;
transition-duration: 0.3s;
transition-property: opacity, margin, transform;
transform: scale(0.2);
}
ul.dropdown-option.vertical {
flex-direction: column;
}
ul.dropdown-option .emoji-icon--dropdown {
max-width: 25px;
margin-left: 10px;
transition: transform 0.2s;
}
ul.dropdown-option .emoji-icon--dropdown:hover {
transform: scale(1.1);
}
ul.dropdown-option::before {
content: "";
border: 10px solid transparent;
border-bottom-color: #fff;
position: absolute;
top: -10px;
transition: top 0.3s;
}
.option:hover ul.dropdown-option {
overflow: visible;
opacity: 1;
width: auto;
transform: scale(1);
margin-bottom: -130px;
}
.option:hover ul.dropdown-option.vertical {
margin-bottom: -180px;
}
.option:hover ul.dropdown-option::before {
top: -19px;
}
.option ul.dropdown-option li {
cursor: pointer;
}
#bb--emojis:active, #bb--align:active {
transform: scale(1.1) !important;
}
#bb--align ul.dropdown-option .align-item {
margin-bottom: 10px;
transition: transform 0.2s;
}
#bb--align ul.dropdown-option .align-item:last-child {
margin-bottom: 0;
}
#bb--align ul.dropdown-option .align-item:hover {
transform: scale(1.1);
}
Bu kodlarda, "Align" ve "Emoji" seçeneklerinin dropdown menülerine gereken stilleri veriyoruz.
Şimdi JavaScript kodlarımıza geçelim. Gerektiği zaman CSS kodlarına ekleme yapmaya devam edeceğiz.
function $(elem) {
return document.querySelector(elem);
}
İlk önce böyle bir fonksiyon oluşturuyoruz. Peki bu fonksiyon ne işe yarıyor? Eğer jQuery bilginiz varsa muhtemelen anlayacaksınızdır, biz bir elementi seçerken uzun uzun document.querySelector()
yazmak yerine sadece $()
yazarak aynı kodun karşılığını alacağız. Bu da bize vakitten kazanç sağlayacak.
var msgBox = $("textarea#textarea");
var outputBox = $("#output");
var bbBold = $("#bb--bold");
var bbItalic = $("#bb--italic");
var bbUl = $("#bb--ul");
var bbOl = $("#bb--ol");
var bbLink = $("#bb--link");
var bbNewLine = $("#bb--new-line");
var alignRight = $("#bb--align #align-right");
var alignCenter = $("#bb--align #align-center");
var alignLeft = $("#bb--align #align-left");
var emoji1 = $("#bb--emojis #e-1");
var emoji2 = $("#bb--emojis #e-2");
var emoji3 = $("#bb--emojis #e-3");
var emoji4 = $("#bb--emojis #e-4");
var emoji5 = $("#bb--emojis #e-5");
var submitBtn = $("button#submit");
Bu satırlarda, kullanacağımız elementleri değişkenlere atıyoruz.
bbBold.addEventListener("click", function () {
msgBox.value = msgBox.value += "[bold][/bold]";
});
Bu blokta; kalın bir yazı yapmak istediğimizde kullanılacak olan BBCode'u msgBox
'ın değerine ekliyoruz. Bu kodun ne olduğunu anlattık. Şimdi geri kalanları vereyim. Bunu anladıysanız aşağıdakileri anlamanız çok zor olmayacak.
bbItalic.addEventListener("click", function () {
msgBox.value = msgBox.value += "[italic][/italic]";
});
bbUl.addEventListener("click", function () {
msgBox.value = msgBox.value += "[ul]\n[li][/li]\n[/ul]";
});
bbOl.addEventListener("click", function () {
msgBox.value = msgBox.value += "[ol]\n[li][/li]\n[/ol]";
});
bbLink.addEventListener("click", function () {
msgBox.value = msgBox.value += '[link="http://"][/link]';
});
bbNewLine.addEventListener("click", function () {
msgBox.value = msgBox.value += "[nl]";
});
// Aligns
alignRight.addEventListener("click", function () {
msgBox.value = msgBox.value += "[align=right][/align]";
});
alignCenter.addEventListener("click", function () {
msgBox.value = msgBox.value += "[align=center][/align]";
});
alignLeft.addEventListener("click", function () {
msgBox.value = msgBox.value += "[align=left][/align]";
});
// Emojis
emoji1.addEventListener("click", function () {
msgBox.value = msgBox.value += ":)";
});
emoji2.addEventListener("click", function () {
msgBox.value = msgBox.value += ":D";
});
emoji3.addEventListener("click", function () {
msgBox.value = msgBox.value += "XD";
});
emoji4.addEventListener("click", function () {
msgBox.value = msgBox.value += "(:";
});
emoji5.addEventListener("click", function () {
msgBox.value = msgBox.value += ":perfect:";
});
Burada olanları tek tek inceleyerek çok da zorlanmadan anlayabileceğinizi düşünüyorum.
submitBtn.addEventListener("click", function () {
outputBox.innerHTML = msgBox.value;
outputBox.innerHTML = outputBox.innerHTML.replaceAll("[bold]", '<span class="bold">')
.replaceAll("[/bold]", "</span>")
.replaceAll("[italic]", '<span class="italic">')
.replaceAll("[/italic]", "</span>")
.replaceAll('[link="', '<a target="_blank" href="')
.replaceAll('"]', '">')
.replaceAll("[/link]", "</a>")
.replaceAll("[li]", "<li>")
.replaceAll("[/li]", "</li>")
.replaceAll("[ul]", "<ul>")
.replaceAll("[/ul]", "</ul>")
.replaceAll("[ol]", "<ol>")
.replaceAll("[/ol]", "</ol>")
.replaceAll("[nl]", "<br/>")
.replaceAll("[align=right]", '<p class="align-right">')
.replaceAll("[align=center]", '<p class="align-center">')
.replaceAll("[align=left]", '<p class="align-left">')
.replaceAll("[/align]", "</p>")
.replaceAll(':)', '<img src="https://twemoji.maxcdn.com/2/72x72/1f642.png" class="emoji-icon" />')
.replaceAll(':D', '<img src="https://twemoji.maxcdn.com/2/72x72/1f604.png" class="emoji-icon" />')
.replaceAll('XD', '<img src="https://twemoji.maxcdn.com/2/72x72/1f923.png" class="emoji-icon" />')
.replaceAll('(:', '<img src="https://twemoji.maxcdn.com/2/72x72/1f643.png" class="emoji-icon" />')
.replaceAll(':perfect:', '<img src="https://twemoji.maxcdn.com/2/72x72/1f60d.png" class="emoji-icon" />');
});
Ve işte en önemli bölüme geldik. Bu bölümü baştan aşağıya anlayacağınız bir şekilde özetlemeye çalışacağım. Eğer aklınıza takılan bir yer olursa sorabilirsiniz. 🙂 En temelinde; "Submit" butonuna tıklandığında gerçekleşecek olan eylemleri belirliyoruz.
outputBox.innerHTML = msgBox.value;
ile, outputBox
'ın değerini, editörümüzün değeri ile eşleştiriyoruz. Yani, editörde ne yazıyorsa outputBox
'a geçiyor.
Sonraki kodlarda bulunan mantığı anlatacak olursak; örneğin outputBox.innerHTML = outputBox.innerHTML.replaceAll("[bold]", '<span class="bold">').replaceAll("[/bold]", "</span>")
bölümünde, eğer outputBox
'ın içinde "[bold]" bloğu geçiyorsa, onu <span class="bold">
değeri ile değiştiriyoruz. Sonrasında, eğer "[/bold]" bloğu varsa, onu </span>
kapanış etiketi ile değiştiriyoruz. Temel olarak böyle. Burada dikkat etmeniz gereken nokta, replaceAll()
fonksiyonunu kullanıyoruz. Bu fonksiyon ile, verdiğimiz 1. parametrede yer alan bütün değerleri, verdiğimiz 2. parametrede yer alan değerler ile değiştiriyoruz. Eğer sadece replace()
fonksiyonunu kullansaydık, önüne çıkan ilk BBCode'u değiştireceği için sistem tam olarak çalışmayacaktı.
Şimdi tekrar CSS'e dönelim. Yukarıda replaceAll()
fonksiyonunu kullanarak değiştirdiğimiz bloklara dikkat ederseniz ne yapmak istediğimi daha rahat anlayacaksınızdır.
/*- BBCodes -*/
span.bold {
font-weight: 900;
}
span.italic {
font-style: italic;
}
p.align-right {
text-align: right;
}
p.align-center {
text-align: center;
}
p.align-left {
text-align: left;
}
Bu kodlarda, yukarıdaki JavaScript kodlarında replaceAll()
fonksiyonunu kullanarak değiştirdiğimiz bloklara gereken stil özelliklerini veriyoruz.
/*- Emojis -*/
img.emoji-icon {
max-width: 17.5px;
height: auto;
cursor: pointer;
}
Bu blokta da; class'ı emoji-icon
olan <img>
etiketlerimize genişlik, yükseklik gibi özellikleri veriyoruz.
Hepsi bu. 🙂 Eğer aklınıza takılan bir yer olursa veya hata alırsanız benimle iletişime geçebilirsiniz. Şunu da eklemek istiyorum; ben sadece responsive olmayan editörün kodlarını verdim, yani en temel kodları yazdım. Eğer kullanacaksanız geri kalan özelleştirmeleri yapmak sizin elinizde.
Eğer hazır kodlara ulaşmak istiyorsanız: https://codepen.io/fatihege/pen/xxEaVgv
Eğer sadece çıktıya ulaşmak istiyorsanız: https://codepen.io/fatihege/full/xxEaVgv