How to get selection HTML and selection parent? - javascript

Several of years ago, I added "smart quoting" to a web forum. Basically, user selects a part in previous conversation and clicks a button to quote it. Script gets the HTML of the quote and goes up the DOM tree to figure out who said that.
I could only do it for IE, although I remember trying hard. But then, there was no stackoverflow.com and Firefox was not as mature. I guess that by now, doing it in Firefox is as easy. Here's the key part of the code.
range2Copy = frameDoc.selection.createRange();
html2Copy = range2Copy.htmlText;
el = range2Copy.parentElement();
// go up the HTML tree until post row node (id=postrowNNNN)
while (el.nodeName != 'BODY' &&
!el.id.match(/postrow/)) {
el = el.parentNode;
}
Element frameDoc contains the previous thread where user selects text. If it makes too little sense, see the whole code here. It is a plugin for FCKeditor.

OK, I tried to run your code in firefox and it didn't work, this is the modified version that worked:
var selection = window.getSelection();
var node = selection.anchorNode;
while (node.nodeName != 'BODY' && !node.id.match(/postrow/)){
node = node.parentNode;
}

Related

Not being able to edit an element top/left css attributes

So, I need to hide a duplicated entry when the 'All sectors' filter is selected but and drag the last entry to cover up the hole it leaves. I made this snippet of code below to do the described action. But it only works when ran from the browser console, it seems to ignore my instructions when put into the js file. I tried putting it in different places throughout the document but i've had no luck so far.
Snippet:
if (window.location.hash == '' || window.location.hash == '#'){
accuGroup = $('a[href*="/en/company/accurate-group/"]').parent().hide()
topval = accuGroup.css('top');
leftval = accuGroup.css('left');
lastArticle = $('article:last-child')
lastArticle.css('top', topval);
lastArticle.css('left', leftval);
} else {
accuGroup = $('a[href*="/en/company/accurate-group/"]').parent().show()
}
You can find a live version here: https://novacap.test.whynotblue.com/en/company/
Additionally, you can find the entirety of the Javascript document here:
https://novacap.test.whynotblue.com/js/main.js?202203021656

JavaScript programatically hover mouse over element

I'm writing a vb.net program to automate and manage an online game. I'm using the Awesomium webcontrols to display and manipulate the pages of the game.
There is a point where I need to grab the data that's not shown in the source until the user hovers over a certain element, how can I use javascript (Not jquery please) to hover over it programatically until the data I need becomes available and then grabbed?
I apologise if this has been asked before (Which it has but from the perspective of someone who owns the web page) but I have been searching for hours for a solution and cant find anything.
What I've tried to use but failed is:
function findBpDate(){
document.getElementById('tileDetails').children[1].children[0].children[1].children[0].fireEvent('onmouseover');
return document.getElementsByClassName('text elementText')[0].textContent;
}
This returns "undefined" when it calls back to my application, I'm certain I'm pointing to the right DOM elements though.
This is what I want the javascript to "hover" on:
<span class="a arrow disabled">Send troops</span>
Once this element has been "hovered" on, this elements text changes to the text I need to grab:
<div class="text elementText">Beginners protection until 20/07/13 07:51 am.</div>
I've shown above what the element looks like when the mouse "hovers" on the element I need it to, however this changes a lot depending on which element the user hovers over while playing the game, from what i gather it's where the source keeps the text for each tooltip in the game.
So I need a function that will hover over a certain element and then while it's hovering, grab the text from the tooltip text/"text elementText" element.
Try WebView.InjectMouseMove(x, y).
Something like
public Point GetElementPosition(dynamic element)
{
dynamic rect = element.getBoundingClientRect();
using (rect)
{
return new Point(rect.left, rect.top);
}
}
dynamic element = webView.ExecuteJavascriptWithResult("document.getElementById('id')");
Point pos = GetElementPosition(element);
webView.InjectMouseMove(pos.X, pos.Y);
this is 10x easier with js/dom. http://jsfiddle.net/pA2Vd/
Do this...assuming you can get reference to elements somehow using by Id would have been lot easier.
var elm = document.getElementsByClassName('a arrow disabled')[0];
var txt = document.getElementsByClassName('text elementText')[0];
var evt = new Event('mouseover');
elm.dispatchEvent(evt);
var status = txt.innerText;
(helpfuL stuff down) otherwise you need to capture event, detect who fired it, check if that has this class and tag name. Lot of processing.
var txt,spn,status='';
document.getElementByTagName('span').forEach(function(d){
if (d.tagName=="div" && d.className == 'text elementText'){
var txt = d;
}
}
window.onmouseover = function(e) {
var elm = e.target;
if (elm.tagName=="SPAN" && elm.className == 'a arrow disabled') {
status=txt.innerText;
}
}

How do I know when a new (Spry) accordion tab has been selected (similar to "on click")? I want to attach my own behaviors

I have an accordion set up to handle registration. I am wanting to validate the data entered on each panel when the user clicks on a different panel tab. I have a continue button on each panel, and am able to validate to my heart's content when the user uses that to go to the next panel.
My problem is that they can also click independently on the accordion tabs (and I want them to be able to skip around for editing purposes), but I would like to validate on those events too.
I've done a bunch of searching, but have not found a satisfactory answer. I am fairly new to Javascript and super-brand-new to jQuery, so please, if you have code snippets for me, be thorough in explaining them.
This should be a straightforward problem (similar to on-click, etc.). I'm quite surprised and frustrated that I haven't found an answer yet.
Edit:
Eric, I couldn't get this to work. Here is my version. I put it in the head section. I have some test code in there that has worked reliably for me in the past (changing the label on one of the tabs). I'm assuming this code has worked for you? Anyway, thanks for your help and I hope we've understood each other sufficiently.
// add capability to detect when accordion tab has been clicked
RegFormAccordion.addEventListener('click', function(e){
var btnElement;
(function findAccordionButton(el){
//e.target is the original element actually clicked on
//the event bubbles up to ancestor/parent nodes which is why you can listen at
//the container
if(!btnElement){ btnElement = e.target; }
else { btnElement = el; }
if(e.target.className !== 'accordionBtn')
{
findAccordionButton(btnElement.parentNode);
}
else
{
var curr_panel_index = RegFormAccordion.getCurrentPanelIndex();
document.getElementById("verify-reg-panel-label").innerHTML = "Index = " + curr_panel_index; // test code to see if it's even getting here
if (curr_panel_index == 1) // contact section
{
ValidateContact();
}
else if (curr_panel_index == 2) // payment section
{
ValidatePayment();
}
UpdateVerifyPanel(); // update contents of verification panel
}
})()
} );
Event delegation.
someAccordianContainer.addEventListener('click', function(e){
var btnElement;
(function findAccordionButton(el){
//e.target is the original element actually clicked on
//the event bubbles up to ancestor/parent nodes which is why you can listen at
//the container
if(!btnElement){ btnElement = e.target; }
else { btnElement = el; }
if(e.target.className !== 'accordionBtn'){
findAccordionButton(btnElement.parentNode);
}
else { doSomething(btnElement); }
})()
} );
You will have to normalize for IE<=8 however if you're supporting older browsers, since it uses a proprietary attachEvent method. Hit quirksmode.org for the details or just use something like jQuery or MooTools.
OK. I found the function that SpryAccordion.js uses to open a new panel and added my own code. Simple and elegant. It's not what I would normally do (usually I leave "libraries" alone). But if you make it editable without giving me another way to take needed control, then the hack is gonna happen.
If I need to use another accordion somewhere else on my website, I will have to double check that I have the correct accordion before invoking the hack. A trade-off I'm willing to make. It works perfectly now. Here is the code:
Spry.Widget.Accordion.prototype.openPanel = function(elementOrIndex)
{
var panelA = this.currentPanel;
var panelB;
if (typeof elementOrIndex == "number")
panelB = this.getPanels()[elementOrIndex];
else
panelB = this.getElement(elementOrIndex);
if (!panelB || panelA == panelB)
return null;
// Start Becca's code
var panelIndex = this.getPanelIndex(panelA);
if (panelIndex == 1) // contact info panel
{
if (ValidateContact())
UpdateVerifyPanel();
else
return null;
}
else if (panelIndex == 2) // payment info panel
{
if (ValidatePayment())
UpdateVerifyPanel();
else
return null;
}
// End Becca's code
var contentA = panelA ? this.getPanelContent(panelA) : null;
var contentB = this.getPanelContent(panelB);
...
...
...
};
Yes, all I wanted was the same control over the panel tabs as I have over my own user-defined buttons, to make sure I could both validate before moving on, and to update my verification screen after any edit the user makes, not just the ones where they happen to hit my continue button. I'm a happy camper. So glad I took a couple of days off.
I hope this helps someone get more control over their own accordions. So glad I don't have to do a crash-course on jQuery when all I want right now is to get my blasted website up.

Specific UIWebView Selections (only entire words/sentences)

I want users to only be able to select an entire sentences within my UIWebView. I'm using my own UIMenuItem (a bookmark button) in a UIWebView. I am going to save this bookmark (core data) and would like to determine which sentence/verse the highlight is in. I am laying out the html programmatically (building up from a sqlite database), and have a <span id="x"> (where x is a variable integer) surrounding every sentence. I know that the Amazon Kindle app only lets users select entire words. How can I do this?
Thanks!
Did you tried setMarkedText:selectedRange:?
Apple developer lib
Update:
While you can't use setMarkedText inside the UIWebView there is no way but using JavaScript. I don't know, if you can manipulate the HTML page that you are showing or not? you can add this script in the page. If you can't manipulate the page you should load an iframe inside your UIWebView that loads your actual page and after the iframe add this script.
Here is the script:
document.addEventListener('mouseup', function(){
if(getSelection().anchorNode != null ){
var sel = getSelection(),
range = sel.getRangeAt(0),
nodeValue = sel.anchorNode.nodeValue,
lastCharIndex = range.endOffset,
firstCharIndex = range.startOffset,
lastChar = nodeValue.substr(lastCharIndex, 1),
firstChar = nodeValue.substr(firstCharIndex, 1);
while(lastChar != (" " || ".")){
lastChar = nodeValue.substr(lastCharIndex, 1);
lastCharIndex++;
};
while(firstChar != " "){
firstChar = nodeValue.substr(firstCharIndex, 1);
firstCharIndex--;
};
range.setEnd(sel.anchorNode, lastCharIndex-1);
sel.addRange(range);
range.setStart(sel.anchorNode, firstCharIndex+2);
sel.addRange(range);
}
}, false);
I tested this on my iPhone and it was working fine.
Here is the Demo (just select something).
I spent a lot time on it. I hope you enjoy it.

How to change behavior of contenteditable blocks after on enter pressed in various browsers

When pressing enter in <div contenteditable="true"> </div> in firefox <br /> is produced - that's ok. But in Chrome or IE a new <div> or <p> is created. What should I do to make Chrome and IE behave like Firefox .
As Douglas said earlier, browsers try to clone previous tag when customer starts a new paragraph on an editable page. The discrepancy occurs when browser has nothing to depart from - e.g. when initially the page body is empty. In this case different browsers behave differently: IE starts to wrap every string into <p> tag, Chrome wraps each line in <div>.
To increase cross-browser experience, WebKit developers have introduced the DefaultParagraphSeparator command. You can use the following JavaScript on page loading for Chrome to change default paragraph separator to <p> tag:
document.execCommand('defaultParagraphSeparator', false, 'p');
The following will add a <br> when the enter key is pressed in all major browsers and attempts to place the caret directly after it. However, WebKit, Opera and IE all have issues with placing the caret correctly after the <br>, which the following code does not attempt to correct.
function enterKeyPressHandler(evt) {
var sel, range, br, addedBr = false;
evt = evt || window.event;
var charCode = evt.which || evt.keyCode;
if (charCode == 13) {
if (typeof window.getSelection != "undefined") {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
br = document.createElement("br");
range.insertNode(br);
range.setEndAfter(br);
range.setStartAfter(br);
sel.removeAllRanges();
sel.addRange(range);
addedBr = true;
}
} else if (typeof document.selection != "undefined") {
sel = document.selection;
if (sel.createRange) {
range = sel.createRange();
range.pasteHTML("<br>");
range.select();
addedBr = true;
}
}
// If successful, prevent the browser's default handling of the keypress
if (addedBr) {
if (typeof evt.preventDefault != "undefined") {
evt.preventDefault();
} else {
evt.returnValue = false;
}
}
}
}
var el = document.getElementById("your_editable_element");
if (typeof el.addEventListener != "undefined") {
el.addEventListener("keypress", enterKeyPressHandler, false);
} else if (typeof el.attachEvent != "undefined") {
el.attachEvent("onkeypress", enterKeyPressHandler);
}
Excellent references are located here on contenteditable.
http://blog.whatwg.org/the-road-to-html-5-contenteditable
Which leads to a really nice API here
http://dev.opera.com/articles/view/rich-html-editing-in-the-browser-part-1/
http://dev.opera.com/articles/view/rich-html-editing-in-the-browser-part-2/
If you're willing to take 30 minutes to an hour to read all this, you will absolutely not have to use some crappy third party editor like tinyMCE or ckeditor or whatever, you can build and customize it yourself and to be frank, it's easier AND faster to do it from scratch than to deal with all the cruft and unnecessary API of a third party WYSIWYG editor.
If you prefer to be happy rather than chase bugs :-) it would be much better to try to make FF use p or div as well. Not just besause it turned out to be a majority vote :-)
The reason is that br alone is borderline illegal if you look at a tag with XML eyes (it injects mixed data model - as in a text that's not guarded by a tag) and the thrend has been for years (by all browsers) towards full XML-ization.
Depending on your actual app it might be worth to try to put a div with fully formed style and definitely with some initial content - if you saw pages where you see grayed-out text like "type your comment here" and it dissapears the second you click into it (or remians - that's a design decision).
The reason for that part is that the semantics of "contenteditable" is "it already has content => browser has enough info to know what to do" so while browsers do their best to do something when faced with no content it makes the situation much more random.
I believe that if the div already has a paragraph tag inside it, and the user presses return while focus is inside that paragraph tag, then Firefox will insert another one. So, if you have this:
<div contenteditable="true">
<p> </p>
<p> </p>
</div>
and you focus, the press return, Firefox will insert a third paragraph.
You might be able to get around having the & nbsp ; in the paragraph tags by giving them minimum heights, and you might be able to get away with having only one. I never got to the bottom of the behaviour to my satisfaction the last time I looked at this. You'll probably need some JavaScript to enforce a minimum of one paragraph tag inside the div.

Categories