So I have HTML text being rendered in a browser (in this case an Android WebView). I want to find out what the (x,y) location in pixels of any given line of text is AFTER it is rendered. The working definition of line I am using is not just all the text contained in a <p> tag or that appears before a <br> tag. I mean a line as it would appear to the user.
I am open to any suggested method.
Is there any CSS property that you are able to find the number of lines in a div and their respective heights? That would provide a workable solution.
Thanks!!
You can't access a line individually. But, with some JavaScript, you can find the position of a line with a known index; here's a basic outline:
var p = document.getElementById("ptag"); //get the text container that contains your line
var nthline = 3; //the line for which you'd like to find the position
var lnheight = parseInt(window.getComputedStyle(p).lineHeight); //get the height of each line
var linepos = [p.offsetLeft, p.offsetTop + lnheight * (nthline - 1)]; //a [left, top] pair that represents the line's position
Note: This assumes the container doesn't have anything but text.
There is no standard way of doing that, you will have to refer to your imagination and invent some hack, right now I can think of two ideas for this:
Enclose each word within a span, like <span
class="word">word</span>, that could easily be done with regex or
string functions, later loop over each <span> reading its
position, add some calculation and you could find out how many
lines, where a line starts (word that incremented its top position
from last one) and when a line ends (last word of line + width of
that word).
Apply some style to first line using :first-line pseudoelement,
like
p:first-line{ background-color: white; /* same existent color so
no affecting display*/ }
later find in DOM what text that style was applied. This idea is not
as good and first one but maybe it can make you think of other ways.
Related
I know how to set the contents of a textitem in Photoshop using code like this
var al = doc.activeLayer;
if(al.kind == LayerKind.TEXT) {
//get the textItem
var ti = al.textItem;
//change contents
ti.contents = "stackoverflow";
}
However is it possible to modify just part of its contents and apply formatting. For example in the work "stackOverflow" I just want to select the first letter and make the font 30px and leave the rest unchanged?
There's no easy way to do that to my knowledge. First of all, it's not possible with DOM, so forget using textItem.contents. With AM the tricky part is that AM code for text layers is really precise. Every time you change something, it defines all possible parameters for all "blocks" of text, for example in this case I had a 35px height text layer written in Gudea font and I changed one letter to 70px: https://pastebin.com/XLP64azz
You may see that there's a lot of garbage in there and the text layer is considered as 3 separate blocks now: letters from 0 to 5 (lines 64-65: stack), from 5 to 6 (lines 217-218: O) and from 6 to 14 (lines 281-282: verflow). A little bit lower to each block there are lines that set the size, for example
desc62.putUnitDouble( cTID('Sz '), cTID('#Pxl'), 35.000000 );
desc62.putUnitDouble( sTID('impliedFontSize'), cTID('#Pxl'), 35.000000 );
I know it's possible to remove most of the excessive descriptors (like if you remove descriptors that define font name, the layer will have the font name it had originally), so I guess it's possible to shrink this huge function to several lines that only change a size of a particular letter, but I didn't try that. I guess the algorithm will be like this:
get font size and text with DOM;
split text to blocks (like from 0 to 1 + from 1 to last character to change a font size of a first letter);
use this function to set parameters to specific blocks;
And there'll be problems if there're several styles already exist in the text layer: you'll have to parse layer contents with AM, get all the styles of all the blocks to find the one you're referring to...
I am looking for a solution where I can remove texts (or replace texts with some characters) in DOM where the position of all DOM elements remain same.
Background
My project capture full source code of web pages from sensitive web pages, however, those sensitive data does not matter and need to be removed prior to transmitting to the server. Captured source code will be later used to recreate what Administrator was seeing (without texts)
Example
Assume this is a page:
<div>Some text here
<input type="button" value="some other text" />
some more text
</div>
So it will be rendered like this by browser:
some text here [some other text]some more text
I need it to be like this:
------ ------ ------ [------- ------ ------]------- ------- ------
Current buggy approach
Currently, I get texts in DOM, count characters between each space, and replace those characters with a dash. unfortunately, it will render like this:
---- ---- --- [---- ----- ----]---- ---- ----
Which as you can see, the position of button and link is completely different from the original.
Purpose
The main purpose is to recreate DOM later on for UX purposes, but without any texts transmitted to a server that might contain sensitive information. Texts can be completely removed, replaced with any characters (I used - in this example), replaced with other texts such as "Lorem ipsum", as long as it is completely removed from source code while preserving the exact location of DOM.
It is used to record mouse click and mouse move positions (X, Y) and show them as a click/move heat-map.
Restrictions
I am not able to change font or codes on target web pages and each element and page might be using a different font for each element.
Ideas?
Looking for help if anyone can come up with an idea about this?
The issue here is that - have different character width than characters used in the real text.
I have thought of scrambling words in all sentences therefor preserve final total width of the text. however, someone might be able to reshuffle them back to original word and it is a security/privacy risk.
I have thought of replacing with multiple dashes based on each word size (and using it currently), but How to get the size of each word in it's specified DOM element? (as each DOM element might use different font, therefore different size for each character) and it could have big performance issue trying to create a hidden div next to each element with their texts just to try to calculate text width of it.
on parent element which have text on it, get computed style for font-size,font-family and letter-spacing and use it in a new div to detect that font's width for space. then put original text on that div and detect width of original text. then divide original text width to space width for that font to detect how many space need to be there to generate same width, and generate those spaces. Issue here is that on some pages that have too many texts, It will be an overkill to browser performance.
Your idea?
Try with this:
// Select 'div','a' and 'input' elements.
// you can add more elements or even select all '*'
$('div,a,input').each(function() {
var contents = $(this).contents();
if (contents.length > 0) {
if (contents.get(0).nodeType == Node.TEXT_NODE) {
// Remove text from children nodes
var elementText = $(this)
.clone() //clone the element
.children() //select all the children
.remove() //remove all the children
.end() //again go back to selected element
.text();
// Replace text
$(this).text(elementText.replace(/[a-zA-Z0-9]{1}/g, '-')).append(contents.slice(1));
}
}
// From input tags we will replace value
if($(this).is('input'))
$(this).val($(this).val().replace(/[a-zA-Z0-9]{1}/g, '-'));
});
Here is a JSFiddle Demo
I've done my research and come across these questions on StackOverflow where people asked this same question but the thing is that they wanted to get the position either in terms of x and y coordinates or column from the left. I want to know what the position of the cursor is with respect to the div's innerHTML.
For example:
innerHTML = "This is the innerHTML of the <b>div</b> and bla bla bla..."
^
Cursor is here
So the result I want for this case is 44. How to do it ?
var target = document.createTextNode("\u0001");
document.getSelection().getRangeAt(0).insertNode(target);
var position = contentEditableDiv.innerHTML.indexOf("\u0001");
target.parentNode.removeChild(target);
This temporarily inserts a dummy text node containing a non-printable character (\u0001), and then finds the index of that character within the div's innerHTML.
For the most part this leaves the DOM and the current selection unchanged, with one minor possible side effect: if the cursor is in the middle of text from a single text node, that node will be broken up into two consecutive text nodes. Usually that should be harmless, but keep it in mind in the context of your specific application.
UPDATE: Turns out you can merge the consecutive text nodes using Node.normalize().
So I have a "cursor" object created like so:
var cursor=document.createElement('span');
cursor.id="currentCursor";
cursor.innerHTML="|";
cursor.style.fontWeight="bold";
cursor.style.position = 'absolute';
cursor.style.marginLeft="-1px";
Then I add it to the page where someone clicks with this:
var selection = window.getSelection();
var currentRange = selection.getRangeAt(0);
currentRange.insertNode(cursor);
The problem I'm running into is in certain places (mainly end of lines) if the cursor object is added it creates a line break before the object. Using insertNode to move it to another area removes the line break. Also if I set the display to "none", wait for a few seconds and then set it back to "inline" the line break is removed.
This seems like maybe a browser bug in adding absolute elements, but I was wondering if someone had a workaround. I've tried setting the width to 0px but it has no effect.
Update
So if I change the cursor to
cursor.style.position = 'static';
It doesn't have random line breaks. However this causes space to be created around the element. Any way to not allow elements to create space around them?
Update 2
Added a fiddle to show the problem:
http://jsfiddle.net/Mctittles/pSg2D/1/
Original code is a bit large but I slimmed it down to highlight this problem.
If you click at the end of the smiley face and then type it causes line 33 to trigger creating a new text node. After typing a couple letters you'll see the cursor object is forced to the next line. Clicking somewhere else to move it makes the lines merge again.
If you un-comment lines 38 and 40 you'll see what I was talking about with making it initially display:none and changing it later. This time it doesn't cause a line break.
I took out some cross-browser code for fiddler, so this might only work in Chrome
However [position:static] causes space to be created around the element.
No, it doesn’t cause it – there is no actual space created “around it”, it’s just the display width of a character plus spacing in the used font, and that gives the span element itself a width that is more than the | character itself. But when you position the element absolutely, you don’t notice that, because it is taken out of the flow, so it doesn’t push the following characters to the right.
My workaround proposal: Don’t put | into the span as innerHTML, but leave it empty – and then implement the line by giving the element a border-left:1px solid. Remove position:absolute, so that it defaults to static.
Then you might probably not like the height your cursor is getting with that – but that can be fixed as well, by setting display to inline-block, and giving it a height as well.
Here, see how you like ’dem apples: http://jsfiddle.net/pSg2D/9/
You should use CSS instead. Using z-index and maybe even float would (atleast should) fix this.
Edit: Always make sure no other styles make it break line!
Is there a way to limit the characters per line in a textarea? For instance, in lines 1-3 of the textarea, only 20 characters are allowed but the lines after that, 50 characters are allowed.
The way the textarea is constructed, I can only limit approximately the same amount of characters per line by changing the width (because it's in a shape of a box). I am not sure if limiting a different amount of characters per line is possible.
I am asking this because I have an image on top of the textarea and when the user types in something, the text goes underneath the part where the image is absolutely positioned. Unless it is possible to float an image inside a text area? :?
Tips on solving this using JavaScript
Of course you can, if you use JavaScript. See the following snippet using jQuery:
var result = jQuery('#result');
var my_textarea = jQuery('#mytext');
my_textarea.on('keyup', function(event){
var el = jQuery(this);
var lines = el.val().split('\n').length;
var chars = el.val().split('').filter(function(v){
return v != '\n';
}).length;
result.html('You have ' + lines + ' lines and ' + chars + ' chars');
});
(demonstration is here: http://jsfiddle.net/tadeck/8krTv/1/)
It counts the number of lines & the number of character, there is no problem in counting characters for each line and disabling ability to add more characters in specific line.
Image positioned within textarea
You said some positioning of an image inside textarea could solve the problem. Of course you can do this too - one of the solutions is to make an image a background for the textarea, and then correct padding from the side you want it to appear, so the text does not overflow the image.
ok what are you trying to achieve do you want the text to be on top of the image or do you want it to the left of the image, an absolutely position element breaks out the natural flow and places itself on the closest parent container grid with relative positioning. If possible post a snippet of html and css on jsfiddle.net
Cheers.