I'm trying to implement a utility to accurately clamp multi-line text to a given maximum number of lines. The approach I'm taking is to binary search the text of the element to find the maximum number of words where if the element contains only those words and an ellipsis, its height is not greater than what I determine is the height for N lines.
Since this is basically a trial-and-error method, I'll need to change an element that's actually rendered and check its size. I'd like it to be some other element than the actual one the user sees, because it'd be weird to have its contents blink around for a bit as the page loads. But since the clamp location will very much depend on the precise styling of the original element, I think what I'll need is to make an exact duplicate of it that's not visible to the user but still has the browser lay it out.
How do I accomplish this using JavaScript or jQuery?
I've considered creating an element at say x=-1000000, y=-1000000, and set its style properties to the uhh... computed style of the original element? I don't think that would actually work because the computed style already considers the current content of the element. What I need is some way to get all the style declarations that apply to the given element; or maybe make the new element an absolutely positioned sibling of the original, but since that's outside the regular block flow, I'm not sure its sizing would work the same.
Or is there some general way to make 'invisible' temporary changes to the style of an element that still let me access what the rendering engine makes of them?
Related
I have implemented a proof of concept to illustrate what I try to achiev https://codesandbox.io/s/html-react-parser-forked-wcxv8?file=/src/index.js
I render an article content, which is fetched from the API but I used an example.html file for simplicity. I need to parse it using html-react-parser because we need to do some transformations before rendering it, but I omitted that part as it's not relevant for the scope of this issue.
Once we have it parsed and rendered, I've added an effect to insert an advertisement banner with a distance of twice the viewport height. As you can see, 4 or 5 banners will be inserted, depending on your viewport height, but that's not the amount of banners that should be inserted as the article continues and the conditions to still apply. Hence, we should see more banners.
What am I doing wrong? Thanks!
It looks like the parsed HTML returns an object of length 112, where the odd numbered indices are string types. By filtering out the elements that are strings and inserting at index + viewPortDistance, you get the correct insertion positions.
I have added console statements to ensure that the ads are actually inserted after the correct nodes.
https://codesandbox.io/s/html-react-parser-forked-0476i
The issue is not the amount of ads, but their position. Your array of articles has 116 elements, but the ref.current.children only 56.
In order to force the number of children to match the article nodes, you can wrap each item in the article array in the span of its own. That way, the articles and the children count will be the same and allow for equal distribution of ads. You can see that in here:
https://codesandbox.io/s/html-react-parser-forked-gvvmd?file=/src/index.js
How do you tell if one element is above another (like after all the z indexes are calculated) with the results from querySelectorAll.
Don't think there is an easy solution, as in there is a browser API you could call and get element "z-height".
You could approach this problem similarly to how rendering engine is working, which stacking elements one on top of the other based on DOM tree depth. Then there is also CSS engine, which changes element positions based on tag types and special rules from CSS, such as z-index, special position properties (relative, absolute, etc.) and even CSS "quirks", for example z-index + opacity changes how elements are stacked.
Based on your goal, you could simplify the parsing and ignore what CSS is doing and only take HTML in consideration. There you have DOM API, which makes traversing the tree structure super easy and the DOM rendering engine will handle all the weird cases of wrong-but-still-working markup.
If you can use jQuery, check
$(element).css("z-index");
I have a piece of HTML which I am displaying inside a UIWebView using Webkit stylesheet attributes. I use Webkit to display the HTML in columns in order to simulate a book.
Only one column is visible at a time (one column represents one page). Now, I am trying to find the range of the visible HTML so that I can insert a span element right before the first visible word.
I managed to get the HTML element which contains the first visible word by using the JavaScript function, document.elementAtPoint(I might have the function name wrong), and changed its CSS class. but that just isn't accurate enough for me. I need it to be accurate up to the first visible word.
The idea is the create a column break at the first visible word when the fontsize is increased or decreased. I can using JavaScript to figure out in which column the element is, and programmatically scroll the user to that column, but first I need to get the element in there.
Can anyone help me?
The CSSOM View Module specification adds caretPositionFromPoint(x, y) to the Document interface, which returns a caret position for the specified x and y co-ordinates. WebKit supports caretRangeFromPoint, a close analogue from an earlier specification, which returns a Range.
It is possible that the word has been hyphenated and thus spans two columns, so rather than wrapping the first word in a span you may wish to consider the more naive approach of inserting the span directly at the cursor point. Here's an example:
var caretPos = document.caretRangeFromPoint(x, y);
if (caretPos)
caretPos.insertNode(document.createElement('span'));
Demo (WebKit only—click to insert spans): http://jsfiddle.net/Jordan/Aw9aV/
One final consideration: it is possible that WebKit will eventually stop supporting caretRangeFromPoint in lieu of caretPositionFromPoint; if so, you will need to adapt your code. Also note that the latter returns a CaretPosition which may not implement the insertNode method. The spec is still at WD, so be mindful that it is still in flux.
Ok, nog entirely sure what you are currently doing, but at the very least I should be able to give some useful tips, as I have some experience building page browsing systems in javascript.
First of all, in CSS3 you can define columns https://developer.mozilla.org/en/CSS3_Columns , which will automatically split up the content into different columns within a single element (where a single column has the full width of the uiwebview) and next add browsing controls which move the entire element containing the element (using css3 3d translations for smooth hardware accelerated motion and you know the width of the columns so you don't need to worry about what the first word on the page is). In which case you don't need to worry about splitting up the column breaks yourself. (Though, as I said, I am not sure to what extend you are already doing this).
Alternatively you may decide to wrap all your content in small inline-blocks (as older column implementations did) or even up to the point of single inline elements, each containing a single word. (Though this doesn't seem necessary anymore)
Lastly, work is being done on http://www.w3.org/TR/css3-regions/ which will make this even easier in the future, but for now it's only available in chrome and ie10
On the other hand, you might already be doing this or I might be missing the point, in which case I would need to see some code before I can give you a more specific answer. (I can think of various javascript tricks to work with letters within a text, but none seem necessary in your case)
I am using WebBrowser.Document.GetElementFromPoint() to get an element at a specific x-y point on a webpage. However, sometimes this feature doesn't work as expected, and it returns elements I don't want. Maybe the ones I want are at the same location, but behind or in front of it?
Two questions:
How does Document.GetElementFromPoint() decide what to get
(since it only returns 1) if there are overlapping elements?
Is there a way to get an element from a point that contains a
specific tag name, or class, or id?
"The element to be returned is determined through hit testing." That is, it will return the topmost element.
There is no way to directly limit your search to a given selector, but you could use the old trick of adjusting z-indices of the returned element to a large negative number, then trying again, then adjusting z-indices, etc. until you've cycled down to the bottom of the stack. That will give you a complete collection of elements at that point, at which time you can filter them based on whatever criteria you want.
I'm developing a web-based text editor without any contentEditable, textarea or input things. The biggest portion of my work is to measure widths of text on the left (right) side from the current caret position and moving the caret in the text.
For example when user presse the DOWN key a current left-offset of the caret must be computed and on the line below a character which's position is most similar must be found.
One very convenient way to do is to use one DOM element per character - I can just look at the offsetLeft property. Also, positioning the caret is much easier. Actually, everything is easier.
However I'm very unsure about the performance implications. I have seen this technique (or similar) used on some web-based JavaScript "IDE"s and it works just fine there.
Do you have any hints, tips?
Do you know some other fast way how to measure width of text. I want to avoid putting sections of a line to a DOM element and measuring its width each time as I think it will be much slower.
EDIT: I'm mostly asking about the main fact of EXISTENCE of many dom elements. How to do the measuring is a different thing.
I've seen this done (unfortunately can't find the link now) by using a canvas object and its measureText() method - basically you can ask a canvas "what size would this piece of text be if i rendered it in this style?" and use that to determine your caret position on the surrounding lines. This is performant, but of course it will only work in HTML5-capable browsers, and maybe not all of them.
But frankly this sounds like a big pain in the neck and probably more trouble than it's worth for an in-browser editor :)
You might be interested in this, which is a javascript implementation of the VI text editor. Unfortunately it does use a textarea, however not in the typical manner.