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.
Related
I have Javascript code that opens ISBNs of books on Amazon using hyperlinks (feel free to try, for example: 0133098648). I would like the URL to open up on a new window with all links clicked in a new tab on that same window. It appears one can only open in a new tab of the current window, or a new window every time.
Is what I am looking to do even possible? I've been reading that something like this is restricted by browsers for security reasons; Maybe there's a work around? I've been pulling my hair out trying to find a solution for this, if I could it would make my life much more easier.
A picture to describe my question: http://imgur.com/a/5lUP4
Please use JSfiddle example: http://jsfiddle.net/mq1efed2 ( Code does not work on Stackoveflow)
<html>
<div><b>ISBN Hyperlinker</b></div>
<textarea id=numbers placeholder="paste isbn numbers as csv here" style="width:100%" rows="8" >
</textarea>
<div><b>Hyperlinked text:</b></div>
<div id="output" style="white-space: pre"></div>
<script>
//the input box.
var input = document.getElementById('numbers');
var output = document.getElementById('output')
var base =
'https://www.amazon.ca/s/ref=nb_sb_noss?url=search-alias%3Daps&field-keywords='
//adding an event listener for change on the input box
input.addEventListener('input', handler, false);
//function that runs when the change event is emitted
function handler () {
var items = input.value.split(/\b((?:\d\s*?){10,13})\b/gm);
// Build DOM for output
var container = document.createElement('span');
items.map(function (item, index) {
if (index % 2) { // it is the part that matches the split regex:
var link = document.createElement('a');
link.textContent = item.trim();
link.setAttribute('target', '_blank');
link.setAttribute('href', base + item.replace(/\D+/g, ''));
container.appendChild(link);
} else { // it is the text next to the matches
container.appendChild(document.createTextNode(item))
}
});
// Replace output
output.innerHTML = '';
output.appendChild(container);
}
handler(); // run on load
</script>
</html>
No, this isn't possible. Web pages cannot dictate whether or not content opens up in tabs or new windows. It's up to the user/browser to decide.
At best, you can open a new window with window.open(), but that doesn't give you control over tabs in a specific window later.
I'm trying to use Javascript to replace the selected text in an arbitrary selected TEXTAREA node in Chrome (! not a content editable div !) The code fragment I see repeated in lots of places to replace selected text basically does this:
var sel = window.getSelection();
var range = sel.getRangeAt(0);
range.insertNode( document.createTextNode("test "));
However, this does not work for input fields such as TEXTAREA or INPUT TYPE=TEXT. The text is inserted BEFORE the TEXTAREA instead of inside it.
There is an alternative method to modify the selection text inside a text area using textarea.selectionStart and textarea.selectionEnd. However, these require figuring out which textarea element is actually active/selected. Chrome/Webkit document.activeElement seems to be broken and has been broken for a long time. I can't figure out any workaround to find the "currently selected textarea". See the bug here...
http://code.google.com/p/chromium/issues/detail?id=14436
You can see a micro-demo of the problem I'm trying to solve here.
http://dj1.willowmail.com/~jeske/_drop/insertIssue/1.html
http://ajaxandxml.blogspot.com/2007/11/emulating-activeelement-property-with.html
Any thoughts on this?
Given a webpage with an arbitrary bit of text selected in an arbitrary TEXTAREA node, without knowing ahead of time what textarea the focus is in, how do I find the active textarea and replace the selected text with some other text?
(( FYI: I'm using this code in a Chrome extension. An in-page javascript content script is extending the page javascript, so I have no idea what the page structure is ahead of time. It needs to work for any webpage. ))
I think the problem you may be having is that the active element changes as a result of clicking the button before your code runs. If you instead use the mousedown event and prevent the default button action, it works fine in Chrome:
http://jsfiddle.net/b3Fk5/2/
It appears that as of 8/23/2012, Chrome does not properly support activeElement, as it is often set to "body" when it shouldn't be.
There may also be some challenges because in my chrome extension, right-clicking to get a context menu might be altering the activeElement.
The solution was to provide a focus handler to create a more reliable activeElement in Chrome, and then use direct interaction with the TEXTAREA to handle the selection replacement.
var dActiveElement = null;
function _dom_trackActiveElement(evt) {
if (evt && evt.target) {
dActiveElement = evt.target;
console.log("focus on: " + dActiveElement.nodeName +
" id: " + dActiveElement.id);
} else {
console.log("focus else..");
}
}
if (document.addEventListener) {
document.addEventListener("focus",_dom_trackActiveElement,true);
}
function insertTextAtCursor(text) {
console.log("insertTextAtCursor : " + text);
if (dActiveElement.nodeName.toUpperCase() == "TEXTAREA") {
console.log("selection in textarea! id: " + dActiveElement.id);
var ta = dActiveElement;
var saveSelectionStart = ta.selectionStart;
var newvalue = ta.value.slice(0,ta.selectionStart) +
text + ta.value.slice(ta.selectionEnd,ta.length);
console.log("output : " + newvalue + ", len : " + newvalue.length);
var newSelectionEnd = ta.selectionStart + text.length;
ta.value = newvalue;
ta.selectionStart = ta.selectionEnd = (newSelectionEnd);
}
}
Conventionally, if I click on a link on a browser and drag, the data that is 'fetched' is the URL and its name, and that can be used by the target application (MS Word or a Java Swing app).
I want to modify the default behavior of a browser on drag to include some more data.
One good application is dragging from a google search results page. For example, as shown in the diagram below, when I drag from anywhere in the first result area (marked in yellow), I want to capture not just the url of the page, but also all additional information (like the links for "Actions", "In Mac OS" links at the bottom of the first result).
I am not sure what I need to get this behavior. Javascript might be one solution I guess (maybe an extension that makes a javascript code run on all the pages that load?), but am not sure at all. Any pointers / tips / suggestions would be useful.
To enable drag and drop, simply add draggable="true" as an attribute on an element.
Example:
<div draggable="true">Little brother</div>
All drag events have a property called dataTransfer which is used to hold the drag data. dataTransfer contains two pieces of information, the data format(MIME) and the stored data. The information is set using event.dataTransfer.setData().
event.dataTransfer.setData("text/plain", "Text to drag");
Here's an example that changes the drag and drop behavior.
Setup:
Go to Google.com using Google Chrome.
Search for anything, like "dog".
Press F12 to open up the Dev console.
Copy and Paste the content of jQuery in the console.
Copy and Paste the content of Drag-N-Drop Script in the console.
Usage:
Drag and drop a search result section from the web browser to a text editor, like wordpad.
Result:
A collection of links should show up in your text editor. The links are markdown styled.
Drag-N-Drop Script
(function () {
// #author Larry Battle (http://bateru.com/news) 12.07.2012
var URLS = {
JQUERY : "http://code.jquery.com/jquery-1.8.3.min.js"
};
var SELECTORS = {
GOOGLE_LINK_SECTIONS : ".g"
};
var getNameAndURLFromLinks = function (el) {
var info = ["Links:\n"];
$(el).find("a").each(function () {
var url = $(this).attr("href");
if (/https?:\/\//.test(url)) {
info.push( "- [" + $(this).text() + "](" + url + ")");
}
});
return info.join("\n");
};
var storeDataInEvent = function (evt) {
var info = getNameAndURLFromLinks($(this));
event.dataTransfer.setData('text/plain', info);
};
var main = function () {
$(SELECTORS.GOOGLE_LINK_SECTIONS)
.attr("draggable", true)
.css("border", "3px orange solid")
.bind("dragstart", storeDataInEvent);
};
if(!window.jQuery){
window.alert("Paste the source of jQuery in the console and then run this script again. URL:" + URLS.JQUERY);
}else if(!/search/.test(document.location.href)){
window.alert("Google for something, then run this script in the console again.");
}
main();
}());
You should be able to create a Google Chrome extension that has this functionality for a set number of websites. Each site should have a different main() function. However, you might be able to create a general algorithm if you test against the top 100 sites.
Info on Drag and Drop: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations
dataTransfer Object: http://help.dottoro.com/ljvspfdo.php
List of MIME: http://en.wikipedia.org/wiki/Internet_media_type
I am using CLEditor in my site and I am facing a problem when using it with IE. The problem is: When you insert image and place it in the editor then insert another image , it will overwrite the prevoius one. With Firefox it will place the new one beside the prevoius one. I contacted the CLEditor and he told me this is a browser sprecific issue. He adivse me to make a work around by checking for IE then collapse the current range to its end using TextRange.collapse() method after the image have been inserted. I tried to make this soultion but I am not expert with Javascript to make it works. I need your help to make it working.
This is the code for inserting the image to the editor area:
.bind(CLICK, function() {
// Insert the image or link if a url was entered
var $text = $popup.find(":text"),
url = $.trim($text.val());
if (url !== "")
execCommand(editor, data.command, url, null, data.button);
// Reset the text, hide the popup and set focus
$text.val("http://");
hidePopups();
focus(editor);
});
This is the solution for this problem. It take three days to solve this because I am not JavaScript expert. I hope this will help.
.bind(CLICK, function() {
// Insert the image or link if a url was entered
var $text = $popup.find(":text"),
url = $.trim($text.val());
if (url !== "")
execCommand(editor, data.command, url, null, data.button);
// Reset the text, hide the popup and set focus
$text.val("http://");
hidePopups();
if ($.browser.msie) {
var editorvalue=editor.$frame[0].contentWindow;
var pos = editorvalue.document.body.innerHTML.length;
var textRange = editorvalue.document.body.createTextRange();
textRange.collapse(true);
textRange.moveEnd("character", pos);
textRange.moveStart("character", pos);
textRange.select();
}
focus(editor);
});
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;
}