How to insert image node between text using javascript? - javascript

I need to insert image between the text where mouse click occurs such that the image inserts itself between the text and not overlap the text as can be seen in this jsfilddle.
$('#box').click(function(ev){
$('img.mover').clone()
.removeClass('mover')
.appendTo('body')
.css('left', ev.pageX-20)
.css('top', ev.pageY-20);
});
After the change basically it should look like mbmnB/img/Nmnbbmn if I click between B and N.

You can convert the text into nodes (span) and then detect the mouse click event on the nodes. Than split the text from that node and insert your image in between :
To convert in text node :
function wrapCharacters(element) {
$(element).contents().each(function() {
if(this.nodeType === 1) {
wrapCharacters(this);
}
else if(this.nodeType === 3) {
$(this).replaceWith($.map(this.nodeValue.split(''), function(c) {
return '<span>' + c + '</span>';
}).join(''));
}
});
}
wrapCharacters($('#box')[0]);
check this fiddle hope it helps:
Fiddle

Put every single letter into a span so that you can detect over which one the mouse is when the click event happens.

You should split your text in two inline parts. So best it would be to use span elements as they are inline and do not introduce newlines.
Later on you should get caret position. You can use this answer to get it: get caret position. Lets say you have your position inside var pos;
Then you can split:
function span(text) {
return '<span>'+text+'</span>';
}
var content = $('#box').html();
var left = span(content.substring(0, pos));
var right = span(content.substring(pos, content.length));
var img = '<img src="your_image.ext"></img>';
$('#box').html(left + img + right);
Note that this code is not tested but just displayes the mechanics.

Related

How to convert links to text using JQuery?

I try to think up function which can replace links to text. Image inside a tag should be moved to the wrapper, the original a should be removed.
JS:
var selectors = 'a.mark-video;a.sp5;a>img[alt!=""]'
selectors = selectors.split(";").join(", ");
$(selectors).each(function() {
var current = this;
if (this.nodeName == "IMG") {
current = this.parentNode;
if (current.nodeName != "A")
current = this.parentNode;
if (current.nodeName != "A")
return false;
current = $(current);
}
var wrapper = current.parent();
var new_context = $().append(current.html());
current.remove();
wrapper.append(new_context);
}
);
The problem is
1) that the image is not inserted into the wrapper
2) if it would be inserted it would not have correct position.
I am experimenting using webextensions API (Firefox addon) and I injected the code to site:
http://zpravy.idnes.cz/zahranicni.aspx
In the debugger you can see two wrappers with class="art ". I have removed the first link but image is not inserted. The second one has not been removed yet when debugger was paused after first iteraction.
I hope you can find out why the image is not appended and how to append it to the original position of the element a. I need to find out position of the element a first, and then to move the image into to correct position - that is before div.art-info.
Note: please do not change the selectors string. This is the users input from form field.
Edit:
Almost there:
function(){
if (this.parentNode.nodeName == "A")
$(this.parentNode).replaceWith($(this));
else
$(this).html().replaceWith($(this)); // error: html() result does not have replaceWith...
}
Is this what you're looking for?
https://jsfiddle.net/4tmz92to/
var images = $('a > img');
$.each(images, function(key, image) {
$(this).parent().replaceWith(image);
});
First select all the images that you want to remove the link from, then loop through them and simply replace the parent() with the image.
I have finally solved the problem:
$(selectors).each(
function(){
if (this.parentNode.nodeName == "A")
$(this.parentNode).replaceWith($(this));
else
$(this).replaceWith(
$(this).html()
);
}
);
This works similar. Novocaine suggested not to use $(this).html() but this would skip some images so I prefer to use it.

Detect click on the inner text of the element without wrapping the text in a second element

I have a Div which is as big as half of my page using CSS:
<div id="bigdiv">
CLICK ON THIS TEXT
</div>
I am trying to write a javascript or jquery code which detects click on the text and not the rest of the element. Is there a way to do that?
Since we cannot listen for events directly on the textNodes themselves, we have to take a more creative path to solving the problem. One thing we can do is look at the coordinates of the click event, and see if it overlaps with a textNode.
First, we'll need a small helper method to help us track whether a set of coordinates exists within a set of constraints. This will make it easier for us to arbitrarily determine if a set of x/y values are within the a set of dimensions:
function isInside ( x, y, rect ) {
return x >= rect.left && y >= rect.top
&& x <= rect.right && y <= rect.bottom;
}
This is fairly basic. The x and y values will be numbers, and the rect reference will be an object with at least four properties holding the absolute pixel values representing four corners of a rectangle.
Next, we need a function for cycling through all childNodes that are textNodes, and determining whether a click event took place above one of them:
function textNodeFromPoint( element, x, y ) {
var node, nodes = element.childNodes, range = document.createRange();
for ( var i = 0; node = nodes[i], i < nodes.length; i++ ) {
if ( node.nodeType !== 3 ) continue;
range.selectNodeContents(node);
if ( isInside( x, y, range.getBoundingClientRect() ) ) {
return node;
}
}
return false;
}
With all of this in place, we can now quickly determine if a textNode was directly below the clicked region, and get the value of that node:
element.addEventListener( "click", function ( event ) {
if ( event.srcElement === this ) {
var clickedNode = textNodeFromPoint( this, event.clientX, event.clientY );
if ( clickedNode ) {
alert( "You clicked: " + clickedNode.nodeValue );
}
}
});
Note that the initial condition if ( event.srcElement ) === this allows us to ignore click events originating from nested elements, such as an image or a span tag. Clicks that happen over textNodes will show the parent element as the srcElement, and as such those are the only ones we're concerned with.
You can see the results here: http://jsfiddle.net/jonathansampson/ug3w2xLc/
Quick win would be to have
<div id="bigdiv">
<span id="text">TEXT HERE</span>
</div>
Script:
$('#text').on('click', function() {
.....
});
Let's alter the content dinamically - I will make the clicking on lala available:
<div id="gig">
<div id="smthing">one</div>lala
<div id="else"></div>
</div>
Script:
var htmlText = $('#gig').text(); //the big divs text
var children = $('#gig').children(); //get dom elements so they can be ignored later
$.each(children, function (index, child) {
var txt = $(child).text().trim();
if (txt != '') { //if a child has text in him
htmlText = htmlText.replace(txt, 'xxx'); //replace it in the big text with xxx
}
});
htmlText = htmlText.split("xxx"); //split for xxx make it arrat
var counter = 0; //the part when the text is added
$.each(htmlText, function (i, el) {
htmlText[i] = el.trim();
if (htmlText[i] != "") { //if there is something here than it's my text
htmlText[i] = '<span id="text">' + htmlText[i] + '</span>'; //replace it with a HTML element personalized
counter++; //mark that you have replaced the text
} else { // if there is nothing at this point it means that I have a DOM element here
htmlText[i] = $(children[i - counter])[0].outerHTML; //add the DOM element
}
});
if (children.length >= htmlText.length) { //you might have the case when not all the HTML children were added back
for (var i = htmlText.length - 1; i < children.length; i++) {
htmlText[i + 1] = $(children[i])[0].outerHTML; //add them
}
}
htmlText = htmlText.join(""); //form a HTML markup from the altered stuff
$('#gig').html(htmlText); // replace the content of the big div
$('#text').on('click', function (data) { //add click support
alert('ok');
});
See a working example here: http://jsfiddle.net/atrifan/5qc27f9c/
P.S: sorry for the namings and stuff I am a little bit tired.
Are you able to do this, is this what you are looking for?
What the code does:
It's making only the text inside the div although the div could have other divs as well, makes only the text that has no HTML container like a div a span a p an a or something like that and alters it adding it in a span and making it available for clicking.
EDIT - Solution without adding wrapping element
Doing this without a wrapping element is quite a hassle. I managed to get it to work, however this will only work for one liners that are centered vertically AND horizontally.
To see the HTML and CSS that goes along with this, see the
jsFiddle: http://jsfiddle.net/v8jbsu3m/3/
jQuery('#bigDiv').click(function(e) {
// Get the x and y offest from the window
margin_top = jQuery(this).offset().top;
margin_left = jQuery(this).offset().left;
// Get the dimensions of the element.
height = jQuery(this).height();
width = jQuery(this).width();
// Retrieve the font_size and remove the px addition
font_size = parseInt(jQuery(this).css('font-size').replace('px', ''));
// Retrieve the position of the click
click_x = e.pageX;
click_y = e.pageY;
// These variables will be used to validate the end result
var in_text_y = false;
var in_text_x = false;
// Determine the click relative to the clicked element
relative_x = click_x - margin_left;
relative_y = click_y - margin_top;
// Determine whether the y-coordinate of the click was in the text
if (relative_y >= (parseFloat(height) / 2) - (parseFloat(font_size) / 2) &&
relative_y <= (parseFloat(height) / 2) + (parseFloat(font_size) / 2))
in_text_y = true;
// This piece of code copies the string and places it in a invisible div
// If this div has the same font styling and no paddings etc... it can
// be used to get the width of the text
text = jQuery(this).text();
text_width = jQuery('#widthTester').html(text).width();
// Determine whether the x-coordinate of the click was in the text
if (relative_x >= (parseFloat(width) / 2) - (parseFloat(text_width) / 2) &&
relative_x < (parseFloat(width) / 2) + (parseFloat(text_width) / 2))
in_text_x = true;
// If the x and y coordinates were both in the text then take action
if (in_text_x && in_text_y)
alert('You clicked the text!');
});
Also, this code can be optimized, since the same calculcation is done multiple times, but I thought that leaving the calculcations there better illustrated what was going on.
Solution by adding a wrapping element
If you put a span around the text, then you can add an onClick event handler to the span.
<div id="bigdiv">
<span>CLICK ON THIS TEXT</span>
</div>
jQuery code
jQuery('#bigdiv span').click(function() {
jquery(this).remove();
});
If you want to go straight through HTML, you can use
<div id="bigdiv" onclick="myFunction();">
and then simply apply the function afterwards in JS:
function myFunction(){
//...
}
EDIT: sorry, if you want the text to be affected, put in <p> around the text or <span> ie.
<div id="bigdiv">
<p onclick="myFuncion();"> TEXT </p>
</div>

simple textarea string replace jquery script

I'm trying to make some simple jquery script that replaces a specific string in the textarea. I've got this know:
$("textarea").bind("keyup", function() {
var text = $(this).val();
text = text.replace(/,,/g, "′");
$(this).val(text);
});
This replaces ,, into the unicode symbol ′. This works, except that the cursors position moves to the last character of the textarea everytime there is a replacement. I want that the cursors goes just after the ′ when there is a replacement. How could I do this ?
Here is my jsfiddle: http://jsfiddle.net/zvhyh/
Edit: thanks for the help guys. I use this now:
http://jsfiddle.net/zvhyh/14/
Here is my take on it:
http://jsfiddle.net/zvhyh/11/
$("textarea").bind("keyup", function() {
var cursorPosition = $('textarea').prop("selectionStart");
var text = $(this).val();
if (text.indexOf(',,') > -1) {
text = text.replace(/,,/g, "′");
$(this).val(text);
$('textarea').prop("selectionStart", cursorPosition - 1);
$('textarea').prop("selectionEnd", cursorPosition - 1);
}
});
Here is your updated fiddle: http://jsfiddle.net/zvhyh/10/
The key is to use selectionStart to get the current position of cursor and setSelectionRange to place the cursor in that position later on.
// get current cursor position
var pos = $(this).val().slice(0, this.selectionStart).length;
// replace the text
$(this).val($(this).val().replace(/,,/g, "′"));
// reset the cursor position
this.setSelectionRange(pos, pos);
Hope that helps.
Update:
Because two characters are being replaced by one character, in the above code the cursor position will skip one character to right. One workaround is to first check if a ",," combo is there, and then use the position as one character before.
Updated fiddle: http://jsfiddle.net/zvhyh/13/
if (text.indexOf(",,") > 0) {
...
pos--;
..

keep track of the position of a div in a textarea

I have a textarea that keeps track of a moveble div like this
$('#content').children().draggable({
drag : function () {
$('#textarea').text("left:" +($(this).position().left) + "px" + "\ntop:" + $(this).position().top + "px");
}
});
The problem is that if i write something in that textarea, it will stop updating the position if i move the div.
If the text in the textarea is like this:
blablablabla
left:10px
top:20px;
blablablablabla
I want to be able to write in the textarea and update the position if i move the div without the other content of the textarea being removed.
someone should be able write whatever they want in the textarea and if they move it, the position will appear a specific place or at the end of what they have written
Any ideas?
Example using ".val" instead of ".text": http://jsfiddle.net/Ydkrw/
".val" will remove the existing text...
Update: based on valentinos answer i did like so: http://jsfiddle.net/8G82U/
But this doesn't work if you write something in the textarea before you move it
This could be something to get you started. This is just a rough design that might help you. Used substring and replace javascript methods.
Fiddle
You could save the string denoting the position in variable, and replace only that string when you drag the div. Like this:
var position;
var oldposition = '';
$('#content').children().draggable({
drag: function () {
position = "left:" + ($(this).position().left) + "px" + "\ntop:" + $(this).position().top + "px";
$('#textarea').val($('#textarea').val().replace(oldposition, position));
oldposition = position;
}
});
http://jsfiddle.net/kCT9f/
Typically when I'm doing something like this I add a replacement keys to the content and replace it when I need to prepare the content.
<textarea>blablablabla {left: 10px} {top: 20px} blablablablabla</textarea>
Update the keywords when the div is moved like this.
$('#content').children().draggable({
drag: function(){
var text = $('#textarea').text();
// Replace Keys
text = replaceLengthKey(text, "left", $(this).position().left);
text = replaceLengthKey(text, "top", $(this).position().top);
// Return changes
$("#textarea").text(text);
}
});
function replaceLengthKey(source, name, value){
// Absolute length units: https://developer.mozilla.org/en-US/docs/CSS/length#Absolute_length_units
return source.replace(RegExp("\\{" + name + ":\\s*[0-9]*(px|mm|cm|in|pt|pc)?\\}", "gm"), "{" + name + ": " + value + "}")
}
Then, when you prepare the content as you want on the server or client, but at least the structure will be consistent.
You can enclose the position text within brackets and then when the div is moved apply a regular expression and change only the text within the brackets. Here is a working example.
var text=$('#textarea').val();
var newPos = "(left:" + ($(this).position().left) + "px" + "\ntop:" +($(this).position().top) + "px)"
text=text.replace(/ *\([^)]*\) */g, newPos);
$('#textarea').val(text);

jQuery: scroll textarea to given position

I have a textarea with lots and lots of text:
<textarea cols="50" rows="10" id="txt">lots and lots of text goes here</textarea>
I want to scroll the textarea down, so the user can see 2000-th character. How can I do this using javasctipt/jQuery?
$('#txt').scrollToCharNo(2000); // something like this would be great
EDIT (my solution)
Well, I managed to make it work myself. The only way I found, is to create a DIV with the same font and width as the textarea, put a SPAN near the needed character and find the position of that span.
I am sure, that somebody might find my solution useful, so i'll paste it here:
jQuery.fn.scrollToText = function(search) {
// getting given textarea contents
var text = $(this).text();
// number of charecter we want to show
var charNo = text.indexOf(search);
// this SPAN will allow up to determine given charecter position
var anch = '<span id="anch"></span>';
// inserting it after the character into the text
text = text.substring(0, charNo) + anch + text.substring(charNo);
// creating a DIV that is an exact copy of textarea
var copyDiv = $('<div></div>')
.append(text.replace(/\n/g, '<br />')) // making newlines look the same
.css('width', $(this).attr('clientWidth')) // width without scrollbar
.css('font-size', $(this).css('font-size'))
.css('font-family', $(this).css('font-family'))
.css('padding', $(this).css('padding'));
// inserting new div after textarea - this is needed beacuse .position() wont work on invisible elements
copyDiv.insertAfter($(this));
// what is the position on SPAN relative to parent DIV?
var pos = copyDiv.find('SPAN#anch').offset().top - copyDiv.find('SPAN#anch').closest('DIV').offset().top;
// the text we are interested in should be at the middle of textearea when scrolling is done
pos = pos - Math.round($(this).attr('clientHeight') / 2);
// now, we know where to scroll!
$(this).scrollTop(pos);
// no need for DIV anymore
copyDiv.remove();
};
$(function (){
$('#scroll_button').click(
function() {
// scrolling to "FIND ME" using function written above
$('#txt').scrollToText('FIND ME');
return false;
}
);
});
Here is a demo (it works!): http://jsfiddle.net/KrVJP/
Since none of the answers actually solved the problem, I'll accept experimentX's one: thank you for putting an effort to help me, I appreciate it!
I am not sure if it will work. Please also check it here. It's seems working for 2000th, 1500th, and 1000th position.
EDIT confused font-size or line-height ???
$(function (){
var height = 2000/$('#txt').attr('cols');
$('#txt').scrollTop(height*13);
$('#txt').selectRange(2000,2000); //this is just to check
});
$.fn.selectRange = function(start, end) { //this is just to check
return this.each(function() {
if (this.setSelectionRange) {
this.focus();
this.setSelectionRange(start, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
});
};
UPDATE How about this one
var height = 1200/$('#txt').attr('cols');
var line_ht = $('#txt').css('line-height');
line_ht = line_ht.replace('px','');
height = height*line_ht;
You can use this jquery plugin

Categories

Resources