Text in clipboard with protractor js - javascript

How can I copy a specific text with protractor ?
I would like to load a text to paste after with this command :
return browser.actions().sendKeys(Keys.CONTROL, 'v').perform();
Sample :
Load my text "test" and after with this command, paste "test"
I would like put a text in my clipboard

can I put a value directly in my ng-model, not use sendKeys ?
Yes, you can directly set the model value via .evaluate():
var elm = element(by.model("mymodel.field"));
elm.evaluate("mymodel.field = 'test';");
Putting a text into clipboard
The idea is to use an existing or dynamically create an input element where you would send the text to, select all the text in the input and copy it with a CTRL/COMMAND + C shortcut.
Sample:
var textToBeCopied = "my text";
// creating a new input element
browser.executeScript(function () {
var el = document.createElement('input');
el.setAttribute('id', 'customInput');
document.getElementsByTagName('body')[0].appendChild(el);
});
// set the input value to a desired text
var newInput = $("#customInput");
newInput.sendKeys(textToBeCopied);
// select all and copy
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "a"));
newInput.sendKeys(protractor.Key.chord(browser.controlKey, "c"));
where browser.controlKey is a cross-platform way to handle CTRL/COMMAND keys:
Using cross-platform keyboard shortcuts in end-to-end testing

Somewhat related to this: I needed to test a dialog, which placed some text in the clipboard when the user pressed the 'Copy' button in the dialog. I wanted to test that the text really got copied to the clipboard. I found this 'copy-paste' library: https://www.npmjs.com/package/copy-paste . "A command line utility that allows read/write (i.e copy/paste) access to the system clipboard. It does this by wrapping pbcopy/pbpaste (for OSX), xclip (for Linux and OpenBSD), and clip (for Windows)." I would say it is a javascript module rather than a command line utility. Anyway, I started using it, as the depenency on xclip (for Linux) was not a problem for me.

Here's the snippet I use with protractor to copy text to the clipboard. I need tabs to be accepted because most of my testing involves cut-and-paste from spreadsheets, where tab is the default column delimiter.
Further, it accommodates nuances in the html body's layout better (overflow: hidden).
function copyToClipboard(browser, text) {
var id = 'someCustomIdToAvoidAliasing';
var newInput = browser.element(by.css("#" + id));
return browser.executeScript(function () {
var el = document.createElement('textarea');
el.setAttribute('id', 'someCustomIdToAvoidAliasing');
el.setAttribute('style', 'position:fixed;z-index:10000;top:0;left:0');
el.onkeydown = function(e) {
if (e.keyCode === 9) {
this.value = this.value + "\t";
return false;
}
};
document.getElementsByTagName('body')[0].appendChild(el);
})
.then(function() {
return newInput.sendKeys(text);
})
.then(function() {
return newInput.sendKeys(protractor.Key.CONTROL, "a", protractor.Key.NULL);
})
.then(function() {
return newInput.sendKeys(protractor.Key.CONTROL, "c", protractor.Key.NULL);
})
.then(function() {
return browser.executeScript(function() {
var el = document.getElementById('someCustomIdToAvoidAliasing');
el.remove();
});
});
}

Related

How to loop through object and if span innerText matches the key, then setAttribute value of that key?

I'm trying to create a chrome extension, that will loop through a certain span innerText and if that value matches it will change that text to hyperlinked text with a URL connected to that specific word.
On the web page there are these tags (chat,flamingo,sample ticket, test, etc.) there is a <span> element within a span element with a class "badge-tag"
What I plan is to have an object with numerous entries, key will represent the text of tag(<span>) and the value will be the URL I want to convert this to.
The html will look something like this so I have to grab the value of document.getElementsByClassName("badge-tag").innerText.
Sample html
<span class="badge-tag"><span>facebook</span></span>
<span class="badge-tag"><span>youtube</span></span>
<span class="badge-tag"><span>twitter</span></span>
<span class="badge-tag"><span>bing</span></span>
I created this JS:
if(typeof listitems === 'undefined'){
const init = function(){
const listitems = document.getElementsByClassName("badge-tag");
const tagMap = {
"facebook":"https://google.com",
"youtube":"https://youtube.com",
"test/obj":"https://docs.gorgias.com",
"instagram/dm":"https://instagram.com"
};
// console.log(tagMap['facebook'])
if(text in tagMap){
console.log("ok")
}
Object.values(listitems).forEach(item => {
const text = item.firstChild;
const link = document.createElement('a');
link.setAttribute("href", tagMap); //test link.setAttribute("href", "https://google.com");
link.setAttribute("target", "_blank");
item.appendChild(link);
link.appendChild(text);
// document.querySelectorAll('.badge-tag a')
// .forEach(function(elem){
// elem.setAttribute('target','_blank');
// })
}
)
}
init();
}
What this code does is converts all the <span> with class "badge-tag" to hyperlinked, I need a way to connect the object tagMap with it so that only the if text is equal to object key, it will add it's respective value.
I understand that I'm missing a good chunk here, as I need For Loop, and probably something else to validate but I'm kinda stuck, any help would be appreciated even if it's just a link to an article.
This is the JsFiddle I was messing with https://jsfiddle.net/94yd2h3g/31/
Thanks!
I made only a few minor modifications to your code:
/* if(text in tagMap){
console.log("ok")
console.log(tagMap[text])
} */
if(typeof listitems === 'undefined'){
const init = function(){
const listitems = document.getElementsByClassName("badge-tag");
const tagMap = {
"facebook":"https://google.com",
"youtube":"https://youtube.com",
"test/obj":"https://docs.gorgias.com",
"instagram/dm":"https://instagram.com"
};
// console.log(tagMap['facebook'])
text = "facebook"
if(text in tagMap){
console.log("ok")
}
Object.values(listitems).forEach(item => {
const text = item.textContent;
if(text in tagMap) {
const link = document.createElement('a');
link.setAttribute("href", tagMap[text]);
link.setAttribute("target", "_blank");
while(item.firstChild)
link.appendChild(item.firstChild);
item.appendChild(link);
}
// document.querySelectorAll('.badge-tag a')
// .forEach(function(elem){
// elem.setAttribute('target','_blank');
// })
}
)
}
init();
}
The text you're looking for is best achieved with Node.textContent. I also added a loop to run through all children and add those, which should make the implementation a bit more flexible. Briefly, you can have a situation where an element's text can be made up of more than one text node and looping through .firstChild accounts for that.
Of course, there are multiple ways to skin a cat. You could create a new normalised text node and destroy the old one, use innerHTML, etc., but this is what seemed simplest to me and required the fewest changes.

How to make javascript handle 'ESCAPE(\u001B)' character?

I want to make website that generate code for Windows 10 Command Prompt which supports 'ESCAPE'(\u001B) character to style string.
You can see examples on HERE.
NOTE: Since this site cannot show ``(\u001B) correctly, I will use ← instead.
The problem is, when I tried to make code that make code for Command Prompt like this:
function cdGenerate() {
var input = document.getElementById('ipText').value;
console.log(`input: ${input}`);
input = checkStyle(input);
console.log(`checkStyle input : ${input}`);
input = checkForeground(input);
console.log(`checkForeground input : ${input}`);
input = checkBackground(input);
console.log(`checkBackground input : ${input}`);
str = input;
console.log(`str: ${str}`);
document.getElementById('spResult').innerHTML = `<code>${str}</code>`;
copy(str);
}
function checkStyle(ori) {
var rtb = '←[';
if (document.getElementById('g-style-reset').checked) { rtb += '0;' }
if (document.getElementById('g-style-bold').checked) { rtb += '1;' }
if (document.getElementById('g-style-underline').checked) { rtb += '4;' }
if (document.getElementById('g-style-inverse').checked) { rtb += '7;' }
rtb = rtb.slice(0, -1);
rtb += 'm';
var rtn = rtb.concat(ori);
return rtn;
}
The result isn't not what I wanted.
I entered TEST in ipText HTML input element and execute cdGenerate(), what I should get is ←[7mTEST like thing in ipResult HTML input element. But I can only get TEST, not ←[7mTEST.
I've tested these codes with ← instead of \u001B and nothing changed.
Furthermore, I need to copy those ←[7mTEST to user's clipboard.
How can I make my javascript code to handle ←(\u001B) correctly(as-is)?
OK. I found how to do it.
I need to show 'ESCAPE' character
I decided to show ← instead. And added comment to <input> 'DO NOT COPY THIS TEXT' like thing. All internal functions uses ← instead of 'ESCAPE' because I only need it when copied to clipboard.
I need to copy 'ESCAPE' character
After copy string into <input>, same variable is used when converting ← to 'ESCAPE'. And I used hidden <div> to paste the string('ESCAPE' included) and copy it to clipboard. If <input> is used, 'ESCAPE' character is not copied properly, so I used <div>. Anyway, the <div>'s content is cleared after copying its content to clipboard.
function copyToClipboard(string) {
$id('hide').innerHTML = string;
var temp = document.createElement('input');
document.body.appendChild(temp);
temp.setAttribute('value', string);
temp.select();
document.execCommand('copy');
document.body.removeChild(temp);
}
I hope my workaround help other people who suffers same problem.

Copy current URL to clipboard

Not sure why this has been so difficult for me today, but for some reason I cannot seem to get it to copy the current URL to the clipboard. Overall, I'm looking for a way to do it without needing to create some hidden text elements.
This is what I'm trying so far:
var shareBtn = document.querySelector(".share-button");
shareBtn.addEventListener('click', function(event) {
var cpLink = window.location.href;
cpLink.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copy command was ' + msg);
} catch (err) {
console.log('Oops, unable to copy');
}
event.preventDefault;
});
When I try to go about it using the .select() I get this error:
t.select is not a function
So I'm not 100% sure what the best way to go about this. Again, without using jQuery (or any other JS library) and not using some sort of hidden textfield.
You can create a temporary DOM element to hold the URL
Unfortunately there is no standard API for clipboard operations, so we're left with the hacky way of using a HTML input element to fit our needs. The idea is to create an input, set its value to the URL of the current document, select its contents and execute copy.
We then clean up the mess instead of setting input to hidden and polluting the DOM.
var dummy = document.createElement('input'),
text = window.location.href;
document.body.appendChild(dummy);
dummy.value = text;
dummy.select();
document.execCommand('copy');
document.body.removeChild(dummy);
2021 update: you can use the Clipboard API like so:
navigator.clipboard.writeText(window.location.href);
ppajer's answer is indeed all that's needed when the browser handles the copying, without any custom handling of clipboard events being involved.
But if you or some library hook into the copy event (say, window.addEventListener('copy', ...) and then if that handler relies on using window.getSelection(), then a 19 year old Firefox issue will bite you. Like MDN says:
It is worth noting that currently getSelection() doesn't work on the content of <textarea> and <input> elements in Firefox, Edge (Legacy) and Internet Explorer.
So, getSelection() returns a non-null result after HTMLInputElement#select, but without providing the actual selected content. Easily fixed by using a non-input element to temporarily hold the URL:
function copyUrl() {
if (!window.getSelection) {
alert('Please copy the URL from the location bar.');
return;
}
const dummy = document.createElement('p');
dummy.textContent = window.location.href;
document.body.appendChild(dummy);
const range = document.createRange();
range.setStartBefore(dummy);
range.setEndAfter(dummy);
const selection = window.getSelection();
// First clear, in case the user already selected some other text
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
document.body.removeChild(dummy);
}
(The above will also work when no custom handler hooks into the copy event.)
this might be one of the simpler ways to do it
window.navigator.clipboard.writeText(textToCopy);
var $temp = $("<input>");
var $url = $('.copy').attr('href');
$('.clipboard').on('click', function() {
$("body").append($temp);
$temp.val($url).select();
document.execCommand("copy");
$temp.remove();
const Toast = Swal.mixin({
toast: true,
position: 'top-end',
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
})
Toast.fire({
icon: 'success',
title: 'URL copied! '
})
})

Copy text from an extjs htmleditor component to the clipboard with the W3C Clipboard API

I needed to copy text from an extjs htmleditor component to the clipboard and then paste it into a text document (word or oppenoffice).
It is possible to achieve this with the W3C clipboard API?
handler:function(){
var one = Ext.ComponentQuery.query('#OneItemId')[0].getValue();
var two = Ext.ComponentQuery.query('#TwoItemId')[0];
document.addEventListener('copy', function(e){
e.clipboardData.setData('text/plain', one);
e.preventDefault();
});
document.addEventListener('paste', function(e){
var values = e.clipboardData.getData('text/html');
two.setValue(values);
});
}
https://fiddle.sencha.com/#fiddle/1cdi
I think you cannot use ClipboardEvent interface, because it represents events providing information related to modification of the clipboard, that is cut, copy, and paste events and since you want to copy on button click there is no such event.
Select and copy text in htmleditor component manually is abit tricky since its DOM representation is <iframe>.
I think solution is something like:
{
xtype:'button',
text:'Copy',
handler:function(){
var one = Ext.ComponentQuery.query('#OneItemId')[0];
var two = Ext.ComponentQuery.query('#TwoItemId')[0];
var editorFrame = one.inputEl.dom,
editorFrameDocument = editorFrame.contentDocument || editorFrame.contentWindow.document;
if(editorFrameDocument) {
var documentSelection, selectionRange;
// Select text in htmleditor iframe body
// IE
if (editorFrameDocument.body.createTextRange) {
selectionRange = editorFrameDocument.body.createTextRange();
selectionRange.moveToElementText(editorFrameDocument.body);
selectionRange.select();
} else if (window.getSelection) {
documentSelection = editorFrameDocument.getSelection()
selectionRange = editorFrameDocument.createRange()
selectionRange.selectNodeContents(editorFrameDocument.body);
documentSelection.removeAllRanges();
documentSelection.addRange(selectionRange);
}
// Copy selected text
editorFrameDocument.execCommand('copy');
}
}
}
Working fiddle
Just add some text to the editor, click "Copy" and paste wherever you want.

How to set focus on child of content editable HTML element

I've been trying to create an advanced text input where users can write hashtags.
The input is a div with contenteditable set true, and the hashtags should be child nodes as I'd allow users to put space inside the hashtags.
My problem is that on some browsers I can not set the focus on the hashtag's child node as the user types. On Chrome/Linux and Safari/OSX it seems to work well, but on Firefox and Chrome/OSX setting the focus don't seem to work. (I haven't got to Windows yet.)
var $elComposer = $('#composer');
var InsertTagPair = function (tagtype) {
var newTag = document.createElement (tagtype);
$(newTag).attr ('contenteditable', 'true');
$(newTag).attr ('class', 'tag');
$elComposer.off ('keypress');
if (window.getSelection) {
var selection = window.getSelection();
if (selection.getRangeAt && selection.rangeCount) {
var range = selection.getRangeAt (0);
range.deleteContents ();
range.insertNode (newTag);
range.selectNodeContents (newTag);
range.collapse (false);
selection.removeAllRanges ();
selection.addRange (range);
};
};
newTag.focus ();
return newTag;
};
var ComposerOnKeyPressed = function (event) {
if (event.charCode == 35) { // #
var contextTag = InsertTagPair ('span');
$elComposer.attr ('contenteditable', 'false');
return false;
};
return event;
};
$elComposer.on ('keypress', ComposerOnKeyPressed);
The above code is the essential part that's not working. See it here in action:
JSFiddle - http://jsfiddle.net/cja963ym/1/
To see a more complete version of the composer that makes more sense see this instead:
JSFiddle - http://jsfiddle.net/g_borgulya/ur6zk32s/15/
Symptom: on Firefox if you type in the editable div and press '#', you manually have to click it by mouse or move the focus with tab to be able to edit the hashtag, while on other platforms it gets the focus when I call newTag.focus() on the element.
I don't know how to move on, even how to debug this problem.
Adding newTag.focus() in the "#" handler made it work in Chrome and Firefox (Win) (it didn't before, but did on IE11, just wanted to let you know)
Fiddle fork : http://jsfiddle.net/ekxo4ra3/
Does that look OK for what you wanted ?

Categories