I am currently writing my own BBCode parser. Now what I would like to do is allow the user to enter BBCode, and then it will write it into HTML and display it has HTML. Yet if they enter HTML it will just show it as plain old HTML. Here is what I have so far:
var replacebbcode = $('#textareainput').val().replace(/(\[((\/?)(b|u|i|s|sub|sup))\])/gi, '<$2>');
$('#posttextareadisplay').html(replacebbcode);
In the above I am just replacing all BBCode with HTML tags. Problem is if a user directly enter HTML it will use that as well. So basically, how can I display BBCode as HTML, but actual HTML as text?
Set the target's text() with the full text; so your HTML tags will be encoded. Then do the BBCode replacement on the encoded HTML:
$('#posttextareadisplay').text( $('#textareainput').val() );
var replacebbcode = $('#posttextareadisplay').
html().
replace(/(\[((\/?)(b|u|i|s|sub|sup))\])/gi, '<$2>');
$('#posttextareadisplay').html( replacebbcode );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<textarea name="" id="textareainput" cols="30" rows="10">
[b]bold[/b] <bold>bold</bold>
</textarea>
<p id="posttextareadisplay"></p>
If you want to replace with regular html tags and restrict to only specific BB tags. This is how it's done with a little help from jQuery and Regular Expression:
const replaceBBCodeAsElements = (jElement, tagMapping = {}) =>
jElement.html(jElement.html().replace(/\[(?<tag>\w+)\](.+?)\[\/\k<tag>\]/g,
(...{ 0: original, 1: tagName, 2: tagContent }) =>
tagMapping.hasOwnProperty(tagName) ? $(tagMapping[tagName]).html(tagContent)[0].outerHTML : original
));
And here is an example of using this function:
const replaceBBCodeAsElements = (jElement, tagMapping = {}) =>
jElement.html(jElement.html().replace(/\[(?<tag>\w+)\](.+?)\[\/\k<tag>\]/g,
(...{ 0: original, 1: tagName, 2: tagContent }) =>
tagMapping.hasOwnProperty(tagName) ? $(tagMapping[tagName]).html(tagContent)[0].outerHTML : original
));
const config = {
'a': '<div class="tag some-special-a-tag" />',
'object': '<span class="tag some-special-object-tag" />',
'pre': '<p class="tag some-special-pre-tag" />',
'test': '<div data-hello="world" class="tag some-special-test-tag" />',
};
$("#input").bind("input", function() {
const jRes = $("#result");
jRes.text(this.value);
replaceBBCodeAsElements(jRes, config);
}).trigger('input');
#input {
width: 400px;
height: 100px;
}
#result {
white-space: pre-wrap;
}
.tag {
display: inline-block;
background: rgba(0,0,0,.1);
padding: 0 4px;
border-radius: 5px;
font-family: monospace;
font-weight: bold;
margin: 0;
box-shadow: 0 0 10px 0 rgba(0,0,0,.6);
}
.some-special-a-tag {
background: rgba(255,0,0,.1);
}
.some-special-object-tag {
background: rgba(0,255,0,.1);
}
.some-special-pre-tag {
background: rgba(0,0,255,.1);
}
.some-special-test-tag {
background: rgba(0,255,255,.1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea id="input">This <p>is</p>
a [a]test[/a] text [pre]with[/pre] [b]some[/b] va[test]lu[/test]e.
And this is how it looks [object]when a [pre]tag inside[/pre] other[/object] tag</textarea>
<div id="result"></div>
The above example, will parse only [a], [object], [pre] and [test] BB tags and convert them according to the creation element they are pointing to.
Note, that the minimum required version of JS is ES2018, because of the RegExp Named Group support.
Related
I need to use Text area like this image.
I should able to click Text A, Text B, Text C, Text D buttons and, once I click any of this button it should add to the Text area and also able remove added text field from the Text area. Can I do it using jQuery UI , jQuery or JavaScript .Kendo UI is also okay. but I'm unable to found my requirement support Kendo component to do this.
I researched and found this http://skfox.com/jqExamples/insertAtCaret.html , but it's not support added text fields removable function,
As was mentioned in my previous comments on your previous post, this cannot be done with a <textarea> element. These elements can only contain text, they cannot contain other elements like <button> or <span> which would be required to make a remove button.
The following is a very lightweight example and it has many pitfalls. It does give you some ideas of how you might look at proceeding.
$(function() {
function calcWordWidth(str, fontfamily, fontsize) {
var word = $("<span>").css({
display: "none",
"font-family": fontfamily,
"font-size": fontsize
}).html(str).appendTo("body");
var width = word.width();
word.remove();
return width;
}
function addCloseButton(pos, st, en, trg) {
var btn = $("<span>", {
class: "closeBtn"
}).html("x");
btn.css({
position: "absolute",
left: pos + "px",
top: "1px"
});
trg.parent().append(btn);
btn.click(function() {
removeText(st, en, trg);
$(this).remove();
});
}
function addText(str, trg) {
var cur = trg.val();
var start = cur.length;
if (start) {
trg.val(cur + " " + str);
} else {
trg.val(str);
}
cur = trg.val();
var end = cur.length;
var width = calcWordWidth(cur, trg.css("font-family"), trg.css("font-size"));
console.log(width);
addCloseButton(width, start, end, $("#txtMessage"));
}
function removeText(start, end, trg) {
var cur = trg.val();
var upd = cur.slice(0, start) + " " + cur.slice(end);
trg.val(upd);
}
$("button").click(function() {
addText($(this).val(), $("#txtMessage"));
});
});
.closeBtn {
font-family: Arial;
font-size: 12px;
cursor: pointer;
padding: 1px;
background: #ccc;
border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="maincontainer">
<div id="navtoplistline"> </div>
<div id="contentwrapper">
<div><button id="btn-1" value="Hello World!">Hello World!</button></div>
<div id="maincolumn">
<div class="text" style="position: relative;">
<textarea name="txtMessage" id="txtMessage" class="txtDropTarget ui-droppable" cols="80" rows="15"></textarea>
</div>
</div>
</div>
</div>
You can also look at using a <div> element with the contenteditable attribute enabled. Again, pretty complex and would not advise it.
As I suggested, you may be better off using something like TinyMCE. TinyMCE is a JavaScript based Rich Text editor that is highly customizable.
Example: https://jsfiddle.net/Twisty/fngjcse3/
JavaScript
tinymce.init({
selector: 'textarea',
menubar: false,
statusbar: false,
plugins: "code",
toolbar: 'helloWorld allBase code',
setup: function(editor) {
var makeSpan = function(str) {
return '<span class="word"> ' + str + ' <em>x</em><span> ';
}
editor.ui.registry.addButton('helloWorld', {
text: 'Hello World!',
onAction: function(_) {
editor.insertContent(makeSpan("Hello World!"));
}
});
editor.ui.registry.addButton('allBase', {
text: 'All your Base',
onAction: function(_) {
editor.insertContent(makeSpan("All your base"));
}
});
},
content_style: 'span.word em { font-style: normal; font-size: 12px; background: #ccc; cursor: pointer; padding: 1px; border-radius: 3px; }',
init_instance_callback: function(editor) {
editor.on('click', function(e) {
if (e.target.nodeName == "EM") {
console.log("Remove Word.");
e.target.parentElement.remove();
}
});
}
});
This initializes TinyMCE with custom buttons. These buttons add the HTML that would be needed. You can also initialize it with custom callbacks, this can handle the close or remove options you are looking for.
Find html character and reduce size, not sure what the function is to do this?
jQuery("body").children().each(function () {
jQuery(this).html( jQuery(this).html().match("•").attr('style', "font-size:'9px'"));
});
As commented,
You will have to set style to element and not string.
To do this, you will have to fetch the string and then wrap matched string in an element with necessary style.
In your code jQuery(this).html().match("•").attr('style', "font-size:'9px'"), .match will return an array of matched values. They are still string and not HTML Element.
Sample
document.getElementById("btn").addEventListener("click", handleClick);
function handleClick(){
var input = document.getElementById("input").value;
if(!input) return;
var p = document.querySelector("p");
var parsed = p.innerHTML.replace(new RegExp(input, "gi"), function(t){
return "<span class='highlight'>" + t + "</span>"
});
p.innerHTML = parsed;
}
.highlight{
font-size: 12px;
border-bottom: 1px dashed gray;
}
span{
font-size: 16px;
}
<p> This is a sample Text</p>
<input type="text" id="input" />
<button id="btn">Update Style</button>
Here I want to randomly change the CSS of each character of text.
Like if I input Stack I will get S in red, t in blue, a in green... etc on the bottom of the input field.
var myModel = {
name: "Mayur",
};
var myViewModel = new Vue({
el: '#my_view',
data: myModel
});
span{
color:green;
font-weight:600;
font-size:20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="my_view">
<label for="name">Enter name:</label>
<input type="text" v-model="name" id="name" name="name" />
<p>Welcome, <span>{{ name | uppercase }}</span></p>
</div>
I haven't worked with Vue and I'm not familiar with its internal events and processes, but here's a tiny prototype i made in plain JavaScript:
document.querySelector('button').onclick = function (){
let span = document.querySelector('span.letters'),
text = span.textContent;
span.innerHTML = '';
Array.from(text).map(function(l){
let color = document.createElement('span');
color.innerHTML = l;
color.style.color = 'rgb(' +
randInterval(0, 255) + ',' +
randInterval(0, 255) + ',' +
randInterval(0, 255) + ')';
span.appendChild(color);
});
}
function randInterval(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
<div><span class="letters">STACK</span></div>
<button>Random colors</button>
I've purposefully placed the function that randomizes each value of rgb() in a function, so you can alter it easily (now the colors are trully random). If you want to make the darker, you need to lower the max values. If you want the colors lighter, you need to increase the mins.
Html:
<div>Type something here, then click on the white space beneave.</div>
<input type="hidden" id="hidden">
Javascript:
$("div").prop("contentEditable", true).blur(function(){
var chars = $(this).text().split("");
$("#hidden").val($(this).text());
this.innerHTML = "";
$.each(chars, function(){
$("<span>").text(this).css({
color: "#"+(Math.random()*16777215|0).toString(16)
}).appendTo("div");
});
});
Css:
div{
border: 1px solid black;
width: 400px;
height: 20px;
padding: 2px 3px;
overflow: hidden;
}
You can visit http://jsfiddle.net/DerekL/Y8ySy/ for the implementation!
Both html and css codes are given in the link.
It gives the colour to the characters randomly but it can be manipulated easily or if you want them to run randomly, you can use it directly.
I would like to display a text copied from a site, for example Wikipedia, in a div. This text has to be strictly without the tags that the computer copies with the text from wikipedia.
I think that the solution is to set a sort of formatting of the text but I don't know.
This is how it should be (Press OK). But I don't want to paste the text in the code, I have to paste the text in the textarea.
In fact if you try to paste something from Wikipedia in the textarea of this Jsfiddle you will see that the result is horrible and with all the html tags.
HTML:
<div id="faketxt" contenteditable></div>
<button id='btn'>OK</button>
<button class="fontStyle" onclick="document.execCommand( 'bold',false,null);" title="Bold Highlighted Text"><b>B</b>
</button>
<button class="fontStyle" onclick="document.execCommand( 'underline',false,null);"><u>U</u>
</button> <br>
<div id='boxes'>
</div>
CSS:
#faketxt {
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
border: 1px solid gray;
height: 28px;
overflow: auto;
padding: 2px;
resize: both;
width: 400px;
}
.fakes{
width: 150px;
height: 300px;
font-size: 10px;
border-style: solid;
display:inline-block;
float: left;
}
#boxes{
display : flex;
display:inline-block;
}
jQuery:
$('#btn').click(function() {
var primo = document.getElementById('faketxt');
var wordLimit = 130;
var words = primo.innerHTML.replace(/(<([^>]+)>)/ig,"").split(/\s/);
if (words.length) {
var count = 0;
var div = createDiv();
var bold = false;
words.forEach(function(word) {
if (++count > wordLimit) {
count = 1;
div = createDiv();
}
if (div.innerHTML) {
div.append(' ');
}
if (word.indexOf('<b>') != -1) {
bold = true;
}
if (bold) {
$(div).html($(div).html() + '<b>' +
word + '</b>');
} else {
$(div).html($(div).html() +
word);
}
if (word.indexOf('</b>') != -1) {
bold = false;
}
});
}
});
function createDiv() {
div = document.createElement('div');
div.className = 'fakes';
document.getElementById('boxes').append(div);
return div;
}
innerHTML or jquery's $.html() will pull the content (including HTML) of an element. But textContent or jquery's $.text() will just get the text.
Instead of var words = primo.innerHTML have you tried using var words = primo.textContent or var words = $(primo).text()?
try using
words = primo.textContent.replace(/(<^>]+)>)/ig,"").split(/\s/);
instead of
words = primo.innerHTML.replace(/(<([^>]+)>)/ig,"").split(/\s/);
Rather than getting the innerHTML of the source, simply get the text content using either the javascript or JQuery text() functions.
So, given you are using jQuery, change your words variable to initialise as follows.
var words = $(primo).text().split(/\s/);
I am trying to get the formatted text from a contenteditable='true' div to send to my server.
I used to use a textarea and when you get the value of a textarea it preserves white space and line breaks, but when using a contenteditable div even when using styles such as the following I can not get the properly formatted text:
white-space: pre-wrap;
word-wrap: break-word;
For example if I type this into my div:
"a
aa
asdf"
I will get this out with textContent:
"a aaasdf"
Is there any way to get formatted text out of a contenteditable div like a textarea?
Use .innerHTML to get the linebreaks too.
Readup: .innerHTML | MDN
Working Code Snippet:
document.getElementById('copy').addEventListener('click', function(){
var text = document.getElementById('input').innerHTML;
document.getElementById('output').innerHTML = text;
});
div{
width: 200px;
height: 200px;
border: 1px solid black;
display: inline-block;
vertical-align: top;
}
<div contenteditable='true' id="input">Enter something funny<br>;)</div>
<button id="copy">Copy Text</button>
<div id="output">Text will be copied here.</div>
Example from: Extracting text from a contentEditable div
function getContentEditableText(id) {
var ce = $("<pre />").html($("#" + id).html());
if ($.browser.webkit)
ce.find("div").replaceWith(function() { return "\n" + this.innerHTML; });
if ($.browser.msie)
ce.find("p").replaceWith(function() { return this.innerHTML + "<br>"; });
if ($.browser.mozilla || $.browser.opera || $.browser.msie)
ce.find("br").replaceWith("\n");
return ce.text();
}
Or:
$.fn.getPreText = function () {
var ce = $("<pre />").html(this.html());
if ($.browser.webkit)
ce.find("div").replaceWith(function() { return "\n" + this.innerHTML; });
if ($.browser.msie)
ce.find("p").replaceWith(function() { return this.innerHTML + "<br>"; });
if ($.browser.mozilla || $.browser.opera || $.browser.msie)
ce.find("br").replaceWith("\n");
return ce.text();
};
This require jQuery, though.
When you enter content into a contenteditable element, this auto-generates HTML nodes within the target element.so you need to access its .innerHTML property and treat the content as HTML, not plain text
You can access this HTML content using the .innerHTML property, or you can use .innerText, which returns plain text but preserves the formatting as shown in #Rahul Desai's answer and in this blog post:
document.getElementById('getText').onclick = function () {
console.log(document.getElementById('edit').innerHTML);
};
<div id='edit' contenteditable='true'>Type here</div>
<input id='getText' type='button' value='Get Text' />
If I enter
Hello
how
are you
into that div and then click the button, the console shows:
<p>Hello</p><p>how</p><p><br></p><p>are you</p>
document.getElementById('getText').onclick = function () {
console.log(document.getElementById('edit').innerHTML);
};
<div id='edit' contenteditable='true'>Type here</div>
<input id='getText' type='button' value='Get Text' />