fatihege
Doçent
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.
HTML:
<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 CSS kodlarımıza geçebiliriz.
CSS:
/*- 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;
}
CSS:
#container {
width: 100%;
height: 100vh;
min-width: max-content;
background: efefef;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
CSS:
#form {
width: 50%;
height: max-content;
background: #0ff;
position: relative;
border-radius: 15px;
min-width: 700px !important;
}
CSS:
.option .top-bar--icon {
width: 25px;
height: auto;
}
CSS:
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;
}
CSS:
textarea#textarea:focus {
box-shadow: 0px 0px 0px 5px rgba(50, 147, 237, 0.4);
}
CSS:
#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;
}
CSS:
#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;
}
CSS:
#top .option:first-child {
margin-left: 0;
}
CSS:
#top .option:hover {
transform: scale(1.1);
}
#top .option:active {
transform: scale(0.9);
}
CSS:
#output {
min-width: 700px;
padding: 15px;
font-size: 17px;
border: 1px solid #a8a8a8;
border-radius: 15px;
margin-top: 4px;
}
CSS:
#output ul, #output ol {
padding-left: 15px;
}
CSS:
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);
}
CSS:
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);
}
Şimdi JavaScript kodlarımıza geçelim. Gerektiği zaman CSS kodlarına ekleme yapmaya devam edeceğiz.
JavaScript:
function $(elem) {
return document.querySelector(elem);
}
JavaScript:
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");
JavaScript:
bbBold.addEventListener("click", function () {
msgBox.value = msgBox.value += "[bold][/bold]";
});
JavaScript:
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:";
});
JavaScript:
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" />');
});
"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.
CSS:
/*- 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;
}
CSS:
/*- Emojis -*/
img.emoji-icon {
max-width: 17.5px;
height: auto;
cursor: pointer;
}
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.
Hazır kodlar: CodePen.io/Pen/
Çıktı: CodePen.io/Full/
Ekran görüntüsü:
Son düzenleme: