Find the Element in which a Range Starts or Ends - javascript

I am trying to find the element in which a Selected Range Starts.
For example:
<p>Hello, <span class="editet">Genei180</span> is My Name</p>
The user now Selects:
"ei180 is My Name"
Therefore i want something like startElementofRange() which Returns "object HTMLSpanElement"
I than want that on keypress only the Part which sits in Span Edíted gets Deleted.
I know about the Node.startOffset and Node.startContainer.
But Node.startContainer would return in this case the whole p-Element as Text Element. But Node.startOffset is in this Case Relative to the Span Element so it would be 2. Also there can be occasions where more than one Span Edited Element can be selected. Current Approach is to loop true them all:
Sitenote:
This is for a Website which allows editing true the Javascript tag Contenteditable='true' and Displays Everything that changed in Green.
I also want to read in only the Changed Parts from the Spans if Submited.
So it can be Disscussed by the Users and Voteaccepted into an Articel.
Is this in general a Secure and sense Making approach?

I searched for weeks...
range.startContainer returns the Notetype but not as i thought of the p Element
instead it returns the type of the Span Element.
So you just need to use range.startContainer.parentNode to get The Element from it.
I feel stupid now.
I leaf this up in case some one has the Same Problem

Related

Cypress - Waiting for an element which has same attributes with other elements already existed

This problem that I'm facing is common for me and I want to learn for about best practices.
My problem is:
I have to wait a text which has an attribute of ".title" class and the text involves the statement of: "Hello". Before triggering this element to come to surface, we have an element already have attributes of ".title" which have a text of "StatementX" as well (At the end of the process, I have 2 ".title" class items on screen).
When I tried to wait for the element "Hello", I write:
`cy.get('.title').contains('Hello').should('be.visible')
`
Since "StatementX" is already on the screen, Cypress finds ".title" class and does not check "contains" part. What is the best practice to handle such cases?
Thank you so much
If you move the class .title into command .contains() it will focus solely on the element you wish to test, i.e two criteria will be tested in one command call and it will find the specific element.
cy.contains('.title', 'Hello').should('be.visible')
If you don't have any difference at all in those elements you will have a return of an array of elements.
In that part .eq(NUMBER OF THE ARRAY) you can validate the option that you want.
Also you can use XPATH for those cases. Not recommended since it's volatile but since is old stuff that is not changed it should have an higher change of stability.

Change span text referring to parent href attribute

I'm looking to change the text on span, but I couldn't target by class nor ID, as they have the same classes, the only difference I spot is the parent link href attribute,
Is there a way I can target them?
Although you could select from the actual text (Customers, Products etc) as this is what will be changed it would only work first time and we aren't told whether the change may need to take place more than once.
A more reliable way would be to select on the hrefs and their ultimate strings.
In CSS this can be done using the $ sign. For example:
a[href$="Customers"]
See MDN.
You add more to this to ensure you target only items in that list.

Can execCommand or a similar function be used to set, rather than to toggle, a simple style like bold?

If a contenteditable div's contents are already bold, then execCommand("bold") will remove the bold style.
That's great in normal circumstances, but I have a situation where I'd like to loop through a bunch of contenteditable divs and set any non-bold text to bold, sort of a way to style multiple rich text elements at once, using the proper or or 'font-weight' whatevers that execCommand uses.
I can do it a hard way by scrutinizing each node in each div in isolation, but I want to make sure there isn't a simpler way first.
It depends on how complex the editor you are making is. If you don't want to allow normal text inside a bold region, it may be enough to test only the deepest containers of editable texts, so one element for each of the editable divs.
Here's an example,
function bold(node) {
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(node);
selection.removeAllRanges();
selection.addRange(range);
if (!isBold(getDeepestContainer(selection.anchorNode)))
document.execCommand("bold");
selection.removeAllRanges();
node.blur();
}
function getDeepestContainer(node) {
var result = node;
while (result.childNodes.length === 1) {
result = result.firstChild;
}
if (result instanceof Element)
return result;
return result.parentElement;
}
http://codepen.io/anon/pen/NqZQzR?editors=101
Okay, I couldn't find an easy way, so I did it the hard way.
I already had a function that copied the contents of a single element to a working space div with clean CSS, and then recursed through each node within that working space. For each text node, it would loop through each style I'm looking for and see if that style is set. If it's NOT, it would clear an "every node has this style" flag set before its run. So I ended up with a list of every style set for every node.
The first step for this current task was to identify which styles applied to all selected elements. So I took that function and created a modified version that first added each element's contents to the working space div. Then it ran the normal recursive walk through the working space, basically treating each separate element as if they're part of the same complex rich text string.
That gave me the status of each style, like whether everything was bold and thus the bold button should show as pressed.
I also added an array for each style. As I recursed through the elements, tracking their individual "every node has this style" value, I would come up with a list of elements where every node had the style, and thus execcommand("bold") would toggle that element.
So now, for each style (like for the bold button), I knew whether it would toggle any elements, or all elements. If it would toggle all elements, or no elements, then that's fine because the behavior's consistent. But if it toggled a subset of elements (if "elements_that_would_toggle" array length for a style was greater than zero but less than the total_elements count), then I would ignore those toggle-able elements on the first button click.
At the end of that click processing, I then blank out those arrays for each style, thus reverting the behavior across the board to toggling, because now every element has been set to the same status.
It's sort of a disgusting approach, but it's controlled and consistent, and it works really well.
And it only took a day to get working.

Search an element's content, excluding content of any children elements

I am having some difficulty figuring this one out. I am trying to search through my list of items and find a number (current day). Then add a css class to that list item.
This is working, but with a slight glitch: I want to be able to exclude all the text that exists inside the <p></p> tags. (Not quite sure how to do this). After some reading, I think I should be using the .not feature, but I think I might be doing it incorrectly.
Here is the jQuery I am currently using:
$("li:contains('" + thisDay + "')").not("p").addClass("current");
For your convenience, I have created this FIDDLE which displays my problem to you.
You will notice that every List Item with the number "19" in it is highlighted.
Could you tell me how to modify only the li that contains 19 and does not search the <p></p> tags for 19 as well?
You have two options. You could wrap the day in a span and target that instead, or you could filter out the text nodes and check them:
http://jsfiddle.net/EfKJ4/
$('.cal').filter(function () {
return $(this).contents()[0].textContent == thisDay;
}).addClass('current');
filter() lets you specify a function to run so you can have more control over the filtering (:contains() only does a wildcard search)
contents() returns all children, including text nodes, which is what your "day" numbers are.
[0] returns the first child, which in this case is the day number. You may want some error checking/handling here to make the solution more robust.
If you return true from the filter callback, the item will be included in the result. Return false, and it won't. So we want to return true when the text content is equal to the day you're looking for.
color property is inherited to the child elements, you can prevent this by simply add the following to your css:
li p{
color:initial;
}
(You can use a more specific selector.)
To downvoters :
This is working, but with a slight glitch: I want to be able to exclude all the text that exists inside the <p></p> tags
Could you tell me how to modify only the li that contains 19 and does not search the <p></p> tags for 19 as well?
OP doesn't want the <p> tags to be affected by the css in .current c;ass. my solution does just that. comments are welcome
Updated Fiddle

Transforming highlighted text inside an element using javascript

My goal is to be able to get the highlighted text within a document, but only if that text is within a given section, and then apply a certain style to that selected text after clicking a div tag. I'll explain what I mean:
So, having looked at window.getSelection() and document.selection.createRange().text, I attempted to use elmnt.getSelection() or elmnt.selection.createRange().text for some HTML element, elmnt. However, it doesn't seem to work, so that idea seems pretty null. This means I can't use this idea to determine the text that is highlighted within a given location. In case this doesn't make sense, essentially, I want html code that looks like this:
<body>
<div id="content">Stuff here will not be effected</div>
<div id="highlightable">Stuff here can be effected when highlighted</div>
<div id="morecontent">Stuff here will also not be effected</div>
</body>
So that whenever I've highlighted text, clicking on a specified div will apply the proper CSS.
Now, on to the div tags. Basically, here's what I've got on that:
$('.colorpicker').click( function(e)
{
console.log(getSelectedText());
}
Eventually, all I want this to highlight the selected text and have the div tag change the color of the selected text to that of the respective div tag that I've selected. Neither of these seems to be working right now, and my only guess for the reason of the div tag is that it unhighlights whatever I've got selected whenever I click on the div tag.
Fallbacks:
If there is more than one time that 'abc' is found on the page and I highlight to color 'abc', I would like that only that copy of 'abc' be highlighted.
I know this is a lot in one question, but even if I could get a little head start on this idea, my next personal project would be going a lot more smoothly. Thanks. :)
The key in the solution to this will be working with the objects that represent text ranges in browsers, not the selected text itself. Look into methods available to you in both the FireFox Range and IE TextRange objects. Both of these contain means of replacing the selected text with your own markup (e.g. a span wrapping your selected text.)
For FF look into Range.getRangeAt(0).surroundContents(element)
For IE look into TextRange.pasteHTML()
I must warn you though... You'll probably end up down a scary path of browser quirks if you go through with this. Already from the get-go you're supporting two different objects for two of the major browsers.

Categories

Resources