So I have a function that registers all the buttons above a textarea, to insert bbcode into that textarea. It works perfectly fine, until I have more than one of these editors on the same page.
Example here: http://codepen.io/anon/pen/JWOzZj
You will see in that example, the second editor's buttons work, but the first does not as it seems to overwrite everything into the last editor made.
I'm not too great with JS, so I'm hoping it's something simple to allow it to be re-used.
Here's the JS code:
/*
* Forked from Octus Editor: https://github.com/julianrichen/octus-editor MIT license
*/
function OctusEditor(editor_id)
{
var editor_bar = 'bar_' + editor_id;
var this_editor = document.getElementById(editor_id);
/*
* init()
*
* Start editor
*/
function init()
{
var quotes = document.querySelectorAll('[data-quote]');
// Register tags
registerElements(editor_bar);
// Register all possible quotes.
for (var x = 0; x < quotes.length; x++)
{
quotes[x].addEventListener("click", registerQuote, false);
}
}
/*
* registerElements()
*
* Register all tags from each editor
*/
function registerElements(id)
{
// Get all styles
var tags = document.querySelectorAll('#' + editor_bar + ' .styles ul li[data-tag]'),
snippet = document.querySelectorAll('#' + editor_bar + ' .styles ul li[data-snippet]');
// register all the tags
for (var i = 0; i < tags.length; i++)
{
// Log editor id
tags[i].editor_id = id;
// Add click event
tags[i].addEventListener("click", registerTag, false);
}
// register all the snippets
for (var x = 0; x < snippet.length; x++)
{
// Log editor id
snippet[x].editor_id = id;
// Add click event
snippet[x].addEventListener("click", registerSnippet, false);
}
}
/*
* registerTag()
*
* Get tag from each editor
*/
function registerTag()
{
// Get textarea
var dataTag = this.dataset.tag;
// Do we have a sub class?
if(this.dataset.subtag)
{
// Fire tag
createTag(dataTag, this.dataset.subtag);
}
else
{
// Fire tag
createTag(dataTag);
}
}
/*
* registerSnippet()
*
* Get tag from each editor
*/
function registerSnippet()
{
// Fire snippet
snippet(this.dataset.snippet);
}
/*
* registerQuote()
*
* Register all quotes
*/
function registerQuote()
{
var username = this.dataset.quote;
var text = this.dataset.comment;
quote(text, username);
}
/*
* quote()
*
* Insert a quote, decodeEntities sorts out the html for the textarea
*/
function decodeEntities(encodedString)
{
var textArea = document.createElement('textarea');
textArea.innerHTML = encodedString;
return textArea.value;
}
function quote(text, name)
{
text = decodeEntities(text);
content = "[quote=" + name + "]" + text;
content += "[/quote]";
this_editor.value += content;
}
/*
* bbcode()
*
* Insert tag
*/
function createTag(tag, subtag)
{
var selected,
ins,
sel,
popUpData;
// Add a sub tag?
if (typeof subtag != 'undefined')
{
subtag = '=' + subtag;
}
else
{
subtag = '';
}
this_editor.focus();
if (typeof this_editor.selectionStart != 'undefined')
{
selected = this_editor.value.slice(this_editor.selectionStart, this_editor.selectionEnd);
}
else if (document.selection && document.selection.type != 'Control') // for IE compatibility
{
selected = document.selection.createRange().text;
}
popUpData = popUp(tag, subtag, selected);
if(popUpData === null || typeof popUpData == 'undefined')
{
return;
}
tag = popUpData[0];
subtag = popUpData[1];
selected = popUpData[2];
ins = '[' + tag + '' + subtag + ']' + selected + '[/' + tag +']';
if (!document.execCommand("insertText", false, ins))
{
this_editor.value = this_editor.value.slice(0, this_editor.selectionStart) + ins + this_editor.value.slice(this_editor.selectionEnd);
}
}
/*
* snippet()
*
* Insert snippet
*/
function snippet(tag)
{
var selected,
ins,
sel;
this_editor.focus();
if (typeof this_editor.selectionStart != 'undefined')
{
selected = this_editor.value.slice(this_editor.selectionStart, this_editor.selectionEnd);
}
else if (document.selection && document.selection.type != 'Control') // for IE compatibility
{
selected = document.selection.createRange().text;
}
popUpData = popUp(tag, selected);
if(popUpData === null || typeof popUpData == 'undefined')
{
return;
}
tag = popUpData[0];
selected = popUpData[1];
ins = tag + selected;
if (!document.execCommand("insertText", false, ins))
{
this_editor.value = this_editor.value.slice(0, this_editor.selectionStart) + ins + this_editor.value.slice(this_editor.selectionEnd);
}
}
/*
* getYouTubeID()
*
* Get YouTube ID
*/
function getYouTubeID(input)
{
var id;
var this_button = document.getElementById('youtube-bbcode');
var yt_limit = this_button.getAttribute('data-limit');
if(input === "")
{
input = window.prompt('Enter YouTube URL, limited to ' + yt_limit + ' per post');
}
id = input.match(/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i);
if(id === null)
{
return null;
}
return id[1];
}
/*
* popUp()
*
* Checks if a pop-up needs to be called
*/
function popUp(tag, subtag, selected)
{
var data;
if(tag == 'youtube')
{
selected = getYouTubeID(selected);
if(selected === null)
{
return null;
}
}
else if(tag == 'url' && selected != "")
{
subtag = window.prompt('Enter a valid URL');
if(subtag === null || subtag === '')
{
return null;
}
else
{
subtag = '=' + subtag;
}
}
else if(tag == 'url' && selected === "")
{
subtag = window.prompt('Enter a valid URL');
if(subtag === null || subtag === '')
{
return null;
}
else
{
subtag = '=' + subtag;
}
selected = window.prompt('URL link text');
if(selected === null || selected === '')
{
selected = 'link';
}
}
data = [tag, subtag, selected];
return data;
}
/*
* Allow keyboard shortcut
*
* All people to use keyboard shortcut
*/
document.onkeydown = function(e)
{
var field = document.getElementById(editor_id);
if (field === document.activeElement)
{
var key = e.keyCode || e.which;
if (e.ctrlKey)
{
switch (key)
{
//http://help.adobe.com/en_US/AS2LCR/Flash_10.0/00000520.html
case 66: // Ctrl+B
e.preventDefault();
createTag(field, 'b');
break;
case 73: // Ctrl+I
e.preventDefault();
createTag(field, 'i');
break;
case 85: // Ctrl+U
e.preventDefault();
createTag(field, 'u');
break;
case 76: // CTRL+L
e.preventDefault();
createTag(field, 'url');
break;
}
}
}
};
// Init
init();
}
And the HTML of the form:
<script type="text/javascript">
window.onload = function() {
OctusEditor('test');
};
</script>
<div id="bar_test" class="octus-editor group">
<div class="styles group">
<ul>
<li data-tag="b" class="bold" accesskey="B">B</li>
<li data-tag="i" class="italic" accesskey="I">I</li>
<li data-tag="u" class="underline" accesskey="U">U</li>
<li data-tag="s" class="strike">S</li>
</ul>
<ul>
<li data-tag="img">img</li>
<li data-tag="url">url</li>
</ul>
<ul>
<li data-tag="code">code</li>
<li data-tag="quote">quote</li>
<li data-tag="spoiler">spoiler</li>
</ul>
</div>
<div class="textarea group">
<textarea name="{:name}" rows="3" cols="17" id="test"></textarea>
</div>
</div>