Copying styled text from a page to the clipboard with Javascript - javascript

I've created a simple tool so employees can personalize their company email signature. This tool creates some styled text with some bolded fonts and a bit of color, nothing fancy. If I then select the text and copy and paste it into my Gmail signature field all works well. It retains the formatting. However, I'd prefer to give the user the option of clicking a "Copy" button that copies the formatted content onto their clipboard.
I'm currently using ZeroClipboard to add the "copy to clipboard" functionality and it's working great. Thing is I don't know how to grab that formatted text. It just keeps copying the unformatted version. One thing I tried was adding a mouseDown listener to ZeroClipboard that selects the text like this:
function selectText() {
if (document.selection) {
var range = document.body.createTextRange();
range.moveToElementText(document.getElementById('clicktocopy'));
range.select();
}
else if (window.getSelection) {
var range = document.createRange();
range.selectNode(document.getElementById('clicktocopy'));
window.getSelection().addRange(range);
}
}
Then returns the selection like this:
function getText() {
if (window.getSelection) {
var range = window.getSelection();
return range.toString();
}
else {
if (document.selection.createRange) {
var range = document.selection.createRange();
return range.text;
}
}
}
However, this is only copying the unformatted text. Is it possible to copy the text formatted?
My formatted text is in a div with the id "results".

If you want an HTML string representing the current selection, the following function will do this (replacing your getText() function):
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}

Related

get selected/highlighted text html in gmail compose mail area

I am designing an chrome extension for Gmail. In this I want to get selected/highlighted text. I tried following code:
if (!window.x) {
x = {};
}
x.Selector = {};
x.Selector.getSelected = function() {
var t = '';
if($('.compose-container').getSelection){
t = $('.compose-container').getSelection();
alert(t);
} else if (window.getSelection) {
t = window.getSelection();
} else if (document.getSelection) {
t = document.getSelection();
} else if (document.selection) {
t = document.selection.createRange().text;
}
return t;
}
It is not giving me selected text in compose mail.
Please help me out.
You would need to use the copy command to achieve this.
var copyText = document.execCommand('copy');
Basically it will copy any text selection in the browser.
You can check out this link on how it was fully utilized
As per gRenzFries answer, I code same as link provided by him. But slight addition in code to paste it in textbox.
Code to Copy text :
var emailLink = document.querySelector('.gmail_default');
var range = document.createRange();
range.selectNode(emailLink);
window.getSelection().addRange(range);
try {
// Now that we've selected the anchor text, execute the copy command
var successful = document.execCommand('copy', true);
} catch(err) {
}
Code to paste it in textbox:
$('#text-to-display').val(""); //reset textbox value
$('#text-to-display').focus(); //set focus to textbox
document.execCommand("Paste");
This code works just as expected.

Text highlighting in html page

I am working in HTML with jquery.
I want to make a webpage to highlight some text lines (line nos 15, 22, 32) in that page at a time. This can be done by left click in mouse and drag that line, so that the text line is selected with blue background.
I am able to get the selected lines as follows using jquery,
function getText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
console.log('text-----------'+text)
}
When I am clicking other line, first selected line was disappears. I need that line also be available. (In MSword, we can hold ctrl and drag the lines and it will be available)
For multiple selection, I know there is more plugins available in web. But I am looking for doing this selection using Javascript or jquery.
This is what I am looking for to do in my page, want to select texts and get them in my javascript function.
How may we do this?
This answer is combined of some issues.
Get the selection text
Mark it.
Copy to clipboard
It's not the full solution but there are all the parts.
So:
var output = '';
$('#test').mouseup(function () {
output += getSelectedText();
highlightSelected();
copyOutput();
$('#result').html(output);
});
function getSelectedText() {
if (window.getSelection) {
return window.getSelection().toString();
} else if (document.selection) {
return document.selection.createRange().text;
}
return '';
}
function highlightSelected() {
var SelRange;
if (window.getSelection) {
SelRange = window.getSelection().getRangeAt(0);
} else if (document.getSelection) {
SelRange = document.getSelection().getRangeAt(0);
} else if (document.selection) {
SelRange = document.selection.createRange();
}
if (SelRange.pasteHTML) {
SelRange.pasteHTML('<span class="hilited1">' + SelRange.text + '</span>');
}
else {
var newNode = $('<span class="hilited1" />')[0];
SelRange.surroundContents(newNode);
}
}
function copyOutput() {
var emailLink = document.querySelector('#result');
var range = document.createRange();
range.selectNode(emailLink);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
try {
var successful = document.execCommand('copy');
} catch (err) {
console.log('Oops, unable to copy');
}
window.getSelection().removeAllRanges();
}
textarea {
width:100%;
height:150px;
}
.hilited1 {
background:red;
color:#fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test">I am working in HTML with jquery.
I want to make a webpage to highlight some text lines (line nos 15, 22, 32) in that page at a time. This can be done by left click in mouse and drag that line, so that the text line is selected with blue background.
I am able to get the selected lines as follows using jquery,
</div>
<hr />
<div id="result"></div>
<hr />
<textarea placeholder="Try to paste here"></textarea>

Convert HTML to plain text in contentEditable

I have a contentEditable and I strip the formatting of pasted content on('paste') by catching the event. Then I focus a textarea, paste the content in there, and copy the value. Pretty much the answer from here. The problem is that I can’t do this:
$("#paste-output").text($("#area").val());
because that would replace my entire content with the pasted text. So I need to paste the content at caret position. I put together a script that does that:
pasteHtmlAtCaret($("#area").val());
// pastes CTRL+V content at caret position
function pasteHtmlAtCaret(html) {
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if (document.selection && document.selection.type != "Control") {
document.selection.createRange().pasteHTML(html);
}
}
The only problem is that it pastes HTML content, at caret position using the html variable. How can I transform that into plain text? I tried adding the jQuery .text(html) to variable without luck. Something like this might help:
el.textContent||el.innerText;
Any ideas or a better solution? Thanks!
EDIT:
Thanks to the answers below I modified my code and solved the issue. I basically copied the value of textarea into a div and grabbed only its .text():
// on paste, strip clipboard from HTML tags if any
$('#post_title, #post_content').on("paste", function() {
var text = $('<div>').html($("#area").val()).text();
pasteHtmlAtCaret(text);
}, 20);
});
Create an external div,
Put your html in that div,
Copy the text from that div
Insert it at the cursor's position.
Upon request from Jonathan Hobbs I am posting this as the answer.
Thanks to the answers above I modified my code and solved the issue. I basically copied the value of textarea into a div and grabbed only its .text():
// on paste, strip clipboard from HTML tags if any
$('#post_title, #post_content').on("paste", function() {
setTimeout(function(){
var text = $('<div>').html($("#area").val()).text();
pasteHtmlAtCaret(text);
}, 20);
});
Replace tag solution:
http://jsfiddle.net/tomwan/cbp1u2cx/1/
var $plainText = $("#plainText");
var $linkOnly = $("#linkOnly");
var $html = $("#html");
$plainText.on('paste', function (e) {
window.setTimeout(function () {
$plainText.html(removeAllTags(replaceStyleAttr($plainText.html())));
}, 0);
});
$linkOnly.on('paste', function (e) {
window.setTimeout(function () {
$linkOnly.html(removeTagsExcludeA(replaceStyleAttr($linkOnly.html())));
}, 0);
});
function replaceStyleAttr (str) {
return str.replace(/(<[\w\W]*?)(style)([\w\W]*?>)/g, function (a, b, c, d) {
return b + 'style_replace' + d;
});
}
function removeTagsExcludeA (str) {
return str.replace(/<\/?((?!a)(\w+))\s*[\w\W]*?>/g, '');
}
function removeAllTags (str) {
return str.replace(/<\/?(\w+)\s*[\w\W]*?>/g, '');
}
The solution I used is to set the innerText of the element on blur:
$element.on('blur', () => this.innerText = this.innerText);
This keeps the whitespace, but strips the formatting. It may work acceptable in your scenario as well.

How to find if a HTMLElement is enclosed in Selected text

Is it possible to find out if an HTMLElement is totally enclosed within the selection?
I have a scenario where user selects some text in a HTML editor and applies some custom style from a list. Now I need to change the class attribute of each span element that is enclosed in that selection and surrounding the selection with a new span with the selected style.
Am able to find out if a particular span element is in selection by using DOM Range's compareBoundaryPoints method in firefox and safari but it will not work for IE.
Is there any way to find out if an element is totally enclosed with in the selected range for IE?
Thanks
Kapil
As #standardModel says, Rangy gives you full* DOM Range support in IE and has a helpful getNodes() method that you could use:
var sel = rangy.getSelection();
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
var spans = range.getNodes([1], function(node) {
return node.nodeName.toLowerCase() == "span" && range.containsNode(node);
});
// Do stuff with spans here
}
If you'd rather not use something as bulky as Rangy, the following function will tell you if an element is completely selected:
function isSelected(el) {
if (window.getSelection) {
var sel = window.getSelection();
var elRange = document.createRange();
elRange.selectNodeContents(el);
for (var i = 0, range; i < sel.rangeCount; ++i) {
range = sel.getRangeAt(i);
if (range.compareBoundaryPoints(range.START_TO_START, elRange) <= 0
&& range.compareBoundaryPoints(range.END_TO_END, elRange) >= 0) {
return true;
}
}
} else if (document.selection && document.selection.type == "Text") {
var textRange = document.selection.createRange();
var elTextRange = textRange.duplicate();
elTextRange.moveToElementText(el);
return textRange.inRange(elTextRange);
}
return false;
}
jsFiddle example: http://jsfiddle.net/54eGr/1/
(*) Apart from handling Range updates under DOM mutation
You may want to take a look at Rangy. This makes xbrowser Ranges and Selections a lot easier.

Javascript: get html around user selection?

It is possible to get whatever the user has selected with the mouse using Javascript, like this: http://www.motyar.info/2010/02/get-user-selected-text-with-jquery-and.html
My issue is that I do not just need this text, but I also need:
to get the html surrounding this text (eg. if the user selects "hello" and this hello is in the source produced as: "<div><span>hello</span></div>" that is what it should return).
to do the same for graphics
Can anyone guide me through this process, or are there alternatives if this is not possible?
This will do it in all major browsers. There are separate branches for IE and more standards-compliant browsers. In IE, it's slightly easier because the proprietary TextRange object created from the selection has a handy htmlText property. In other browsers, you have to use the cloneContents() method of DOM Range to create a DocumentFragment containing a copy of the selected content and obtain the HTML from this by appending the fragment to an element and returning the element's innerHTML property.
function getSelectionHtml() {
var html = "";
if (typeof window.getSelection != "undefined") {
var sel = window.getSelection();
if (sel.rangeCount) {
var container = document.createElement("div");
for (var i = 0, len = sel.rangeCount; i < len; ++i) {
container.appendChild(sel.getRangeAt(i).cloneContents());
}
html = container.innerHTML;
}
} else if (typeof document.selection != "undefined") {
if (document.selection.type == "Text") {
html = document.selection.createRange().htmlText;
}
}
return html;
}
alert(getSelectionHtml());
You can also do like this to get user selected HTML
function getUserSelectedHtml() {
const range = window.getSelection().getRangeAt(0);
const node = document.createElement('div');
node.appendChild(range.cloneContents());
return node.innerHTML;
}

Categories