I am new to Microsoft Office addins and JS. I am trying to develop a Microsoft Word add-in that converts selected text in the document into QR code. So my problem is getting selected text in the document as simple string.
Nothing I tried so far worked. Here is a link for getting the whole text in a document that helped a bit: Word Add-in Get full Document text?. What I need is how to get selected text as a string. I need your help please. I tried the following:
txt = "";
await Word.run(async (context) => {
var documentBody = context.document.body;
context.load(documentBody);
return context.sync().then(function () {
console.log(documentBody.text); //full document text
console.log(document.getSelection.text); //selected only
txt = documentBody.text.getSelection();
});
});
Check the Script Lab. The first sample in Word does exactly what you need:
$("#run").click(() => tryCatch(run));
function run() {
return Word.run(function(context) {
var range = context.document.getSelection();
range.font.color = "red";
range.load("text");
return context.sync().then(function() {
console.log('The selected text was "' + range.text + '".');
});
});
}
/** Default helper for invoking an action and handling errors. */
function tryCatch(callback) {
Promise.resolve()
.then(callback)
.catch(function(error) {
// Note: In a production add-in, you'd want to notify the user through your add-in's UI.
console.error(error);
});
}
I have a web page with some JavaScript code that copies stuff to the clipboard similar to what this demo does: https://davidwalsh.name/demo/javascript-copy-clipboard.php
My code is something like this:
// Within a listener that is triggered by a click on some button:
var copiedText = "...something";
navigator.clipboard.writeText(copiedText).then(
function() {
console.log("Succesfully copied");
},
function() {
console.log("FAILED to copy!!!!!!");
}
);
This works fine, but it always succeeds. I need to test that the behavior is correct when copying fails for whatever reason.
How can I cause the copy to fail on purpose so that I can test the behavior of my code in that situation?
I never get a prompt asking me permission to write to the clipboard.
In Chrome, I have tried going to the site settings for the site, and under "Clipboard" selecting "Block", but it does nothing (I guess that's only for reading from the clipboard).
Sure, just provide an invalid argument which will throw an exception during the stringification algorithm:
Note that this demo will work in your own page, but the success case won't work in the Stack Overflow code snippet iframe sandbox (where there is no clipboard permission).
function copyThenLog (input) {
navigator.clipboard.writeText(input).then(
() => console.log({success: true}),
(ex) => {
console.log({success: false});
console.error(ex);
},
);
}
document.querySelector('.success').addEventListener('click', () => {
const input = 'hello world';
copyThenLog(input);
});
document.querySelector('.fail').addEventListener('click', () => {
const input = {
toString () {
throw new Error('Oops');
}
};
copyThenLog(input);
});
<div class="success">Click me to succeed</div>
<div class="fail">Click me to fail</div>
First of all, I have to say this is my first question on stack ;)
I am trying to implement a reading via NFC on my test web, but i dunno why, the ndefReader doesn't works on startup, i have to press any field on the web to get it loaded (or asked for permission).
BUT, if i wrote some alerts to check why it doen't reach the function on startup, it works!!! (of course, it show alerts before). I don't know if when I accept the alert, I am interacting with the web and that's why it works, but anyways, I dunno why this happens (I need to click anywhere before starting).
function iniciar() {
document.getElementById("input1").focus();
//alert("test before"); <--- IF i remove this, it doesnt works
document.getElementById("input1").addEventListener("blur", async () => {
try{
const ndef = new NDEFReader();
alert("before wait");
await ndef.scan();
alert("after wait");
ndef.addEventListener("readingerror", () => {
alert("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
alert(`> Serial Number: ${serialNumber}`);
alert(`> Records: (${message.records.length})`);
});
} catch (error) {
alert("Argh! " + error);
}
},false);
To scan and write to NFC tags, you must first request the "nfc" permission while handling a user gesture (e.g a button click, or in your case the "alert" call). Once handled, the NDEFReader scan() and write() methods trigger a user prompt, if access was not previously granted.
Check out https://web.dev/nfc/#security-and-permissions to learn more.
Hopefully https://googlechrome.github.io/samples/web-nfc/ samples should help you as well.
scanButton.addEventListener("click", async () => {
console.log("User clicked scan button");
try {
const ndef = new NDEFReader();
await ndef.scan();
console.log("> Scan started");
ndef.addEventListener("readingerror", () => {
console.log("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
console.log(`> Serial Number: ${serialNumber}`);
console.log(`> Records: (${message.records.length})`);
});
} catch (error) {
console.log("Argh! " + error);
}
});
How to get the 'clipboard' content in cypress. I have a button in my web application, on click of button system will perform 'copy to clipboard' and a message will get displayed. Below is an example of the url content that is copy to clipboard ( this url content is different from web site url)
https://someurl.net/machines/0c459829-a5b1-4d4b-b3c3-18b03c1c969a/attachments/a30ceca7-198e-4d87-a550-04c97fbb9231/download
I have double check that there is no href attribute in that button tag. So I have use a plugin called clipboardy and I have added plugins/index.js file
const clipboardy = require('clipboardy');
module.exports = ( on ) => {
on('task', {
getClipboard () {
return clipboardy.readSync();
}
});
};
In my test I have used cy.task() to get the clipboard content, but this is not printing the actual url content
cy.get('td').find('div').find('span').find('button').find('i').eq(0).click().then(()=>{
cy.task('getClipboard').then((data)=>{
console.log("Helloooo:"+data);
})
})
<td class="sc-hgRTRy duUdhJ">
<div>
<span class="sc-bYwvMP jTmLTC">
<span class="sc-jzJRlG iVpVVy">
<span role="button" aria-expanded="true" aria-haspopup="true" aria-owns="5aa03785-1370-455e-a838-4154f7481a7b">
<button class="sc-feJyhm cJOKrG">
<i class="icon fas fa-link sc-htpNat cQABgO" aria-hidden="true" data-component-type="icon">
</i>
</button>
</span>
</span>
</span>
</div>
</td>
If you don't want to use clipboardy package you can also use this:
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq('your copied text');
});
});
in your case, it turns to something like
cy.get('td').find('div').find('span').find('button').find('i').eq(0).click().then(()=>{
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
console.log("Helloooo:"+text);
});
});
})
Accessing clipboard can be worked around, but the main issue is that the document.execCommand('copy') doesn't work (as stated above), which I reckon is the primary (and only?) way for your app to programmatically put a text to user's clipboard.
Assuming it happens somehow (or is fixed upstream), the checking the clipboard's contents can be done e.g. by using clipboardy:
npm i -D clipboardy
plugins/index.js:
const clipboardy = require('clipboardy');
module.exports = ( on ) => {
on('task', {
getClipboard () {
return clipboardy.readSync();
}
});
};
In your specification:
describe('test', () => {
it('test', () => {
cy.document().then( doc => {
doc.body.innerHTML = '<input id="inp">';
});
cy.get('#inp').type('test{selectall}');
cy.document().then( doc => {
doc.execCommand('copy');
});
cy.task('getClipboard').should('contain', 'test');
});
});
I hope this code will be usefull for you.
Thank you.
I have found this nice and simple solution of testing the clipboard content in Gleb Bahmutov's video Access the clipboard from Cypress test using Electron browser.
cy.window().its('navigator.clipboard')
.invoke('readText').should('equal', 'copied text')
It uses the new Clipboard API (Chrome, FF and Opera: 2018; Safari and Edge: 2020; IE: no)
In the video, Gleb also suggets to test a case for browsers not supporting the Clipboard API, using an old (and deprecated) method of document.execCommand('copy').
It expects the page to have an input field or textarea to paste the content. Let's assume it's textarea#paste-here.
// delete navigator.clipboard to force the app to use execCommand
cy.visit('index.html', {
onBeforeLoad(window) {
delete window.navigator.__proto__.clipboard
}
})
cy.document().then(document => cy.spy(document, 'execCommand').as('exec'))
/* trigger the copy action here... cy.get(...).click() */
cy.get('#exec').should('have.been.calledOnceWith', 'copy')
cy.get('#paste-here').focus()
cy.document().invoke('execCommand', 'paste')
cy.get('#paste-here').should('have.value', 'copied text')
Due to the clipboard permissions dialog, this test can be automated (CI) only in Electron browser. To make it running in Chrome, take a look at another Gleb's video Give Chrome Browser Clipboard Permissions from Cypress Test. Otherwise, you can limit the test to be run only in Electron using Test configuration object:
describe('Clipboard', {browser: 'electron'}, () => {
...
Late but if anyone is getting "Document is not focused" error from #marzzy's answer:
cy.window().then((win) => {
win.navigator.clipboard.readText().then((text) => {
expect(text).to.eq('your copied text');
});
});
It's either because:
You are executing code from the devtools console or snippets
Or if you're using Chrome you have to give it clipboard permission like this:
cy.wrap(
Cypress.automation('remote:debugger:protocol', {
command: 'Browser.grantPermissions',
params: {
permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'],
origin: window.location.origin,
},
}),
);
Source: https://www.youtube.com/watch?v=4eEc3x24D64
I managed to get the copied link by printing out the yielded value after clicking the button and then searched the object in the console in order to find the link. I found the link in [object]._vClipboard.clipboardAction.text, as you can see below:
cy.get('[data-test=copy-link-button]').click().then(($clipboard) => {
const copiedLink = $clipboard[0]._vClipboard.clipboardAction.text;
cy.visit(copiedLink);
});
I hope that this will help.
Reading this really helped me solve my own issue, I had to use a mixture from the OP and the first comment. This is what worked for me:
cy.get(':nth-child(2) > .mat-card > .row > .col-sm-3 > .mat-focus-indicator').click().then(() => {
cy.task('getClipboard').then(($clip) => {
const url = $clip;
cy.log('this is what was in clipboard', url);
cy.visit(url);
});
});
This gave me the URL i wanted from the button I clicked. I then just passed that right into cy.visit to visit the url i just copied. Worked great.
For me, none of the answers helped me taking de data from the clipboard. The next code worked:
First we will allow the access to the clipboard:
cy.window().its('navigator.permissions')
.invoke('query', { name: 'clipboard-read' })
.its('state').then(cy.log)
Then we access the clipboard
cy.window().its('navigator.clipboard')
.invoke('readText')
.then((text) => {
cy.log(text)
})
Hope this works for anyone here
Code at https://stackoverflow.com/a/61653634/2742007 should be adapted to call clipboardy functions supported by browsers, as commented by "opike": mind the async and read() instead of readSync().
const clipboardy = require('clipboardy');
module.exports = (on, config) => {
on('task', {
async getClipboard() {
return clipboardy.read();
}
});
}
Note: Above usage of window.navigator https://stackoverflow.com/a/68871590/5667941 , only works for Electron. For Chrome user permisson would be required
Try using cy.window() and you can use the navigator.clipboard as normal for pasting and copying.
it("Paste cliboard numbers", () => {
cy.window()
.then((win) => {
return win.navigator.clipboard.writeText("234");
`})`
.then(() => {
cy.get("[data-test=paste]").click();
cy.get("[data-test=calc-input]").should("have.text", 234);
});
});
None of the other answares worked for me so far with the cypress ui but I managedto find a solution without any additional libs or plugins by using the Cypress.Promises and the window.navigator directly ... and here it is:
cy.window().then(win =>
new Cypress.Promise((resolve, reject) =>
win.navigator
.clipboard
.readText()
.then(resolve)
.catch(reject))
).should('eq', '`myExpectedClipboardValue')
You have to give clipboard read permission.Befor click button to have copied text add this.
cy.wrap(Cypress.automation("remote:debugger:protocol", {
command: "Browser.grantPermissions",
params: {
permissions: ["clipboardReadWrite", "clipboardSanitizedWrite"],
// make the permission tighter by allowing the current origin only
origin: window.location.origin
}
}));
I have made a solution for my website which includes using ajax to present the general information on the website. In doing this, I am changing the URL every time a user loads some specific content with the window.history.pushState method. However, when I press backspace or press back, the content of the old url is not loaded (however the URL is loaded).
I have tried several solutions presented on SO without any luck.
Here is an example of one of the ajax functions:
$(document).ready(function(){
$(document).on("click",".priceDeckLink",function(){
$("#hideGraphStuff").hide();
$("#giantWrapper").show();
$("#loadDeck").fadeIn("fast");
var name = $(this).text();
$.post("pages/getPriceDeckData.php",{data : name},function(data){
var $response=$(data);
var name = $response.filter('#titleDeck').text();
var data = data.split("%%%%%%%");
$("#deckInfo").html(data[0]);
$("#textContainer").html(data[1]);
$("#realTitleDeck").html(name);
$("#loadDeck").hide();
$("#hideGraphStuff").fadeIn("fast");
loadGraph();
window.history.pushState("Price Deck", "Price Deck", "?p=priceDeck&dN="+ name);
});
});
Hope you guys can help :)
pushState alone will not make your page function with back/forward. What you'd need to do is listen to onpopstate and load the contents yourself similar to what would happen on click.
var load = function (name, skipPushState) {
$("#hideGraphStuff").hide();
// pre-load, etc ...
$.post("pages/getPriceDeckData.php",{data : name}, function(data){
// on-load, etc ...
// we don't want to push the state on popstate (e.g. 'Back'), so `skipPushState`
// can be passed to prevent it
if (!skipPushState) {
// build a state for this name
var state = {name: name, page: 'Price Deck'};
window.history.pushState(state, "Price Deck", "?p=priceDeck&dN="+ name);
}
});
}
$(document).on("click", ".priceDeckLink", function() {
var name = $(this).text();
load(name);
});
$(window).on("popstate", function () {
// if the state is the page you expect, pull the name and load it.
if (history.state && "Price Deck" === history.state.page) {
load(history.state.name, true);
}
});
Note that history.state is a somewhat less supported part of the history API. If you wanted to support all pushState browsers you'd have to have another way to pull the current state on popstate, probably by parsing the URL.
It would be trivial and probably a good idea here to cache the results of the priceCheck for the name as well and pull them from the cache on back/forward instead of making more php requests.
This works for me. Very simple.
$(window).bind("popstate", function() {
window.location = location.href
});
Have same issue and the solution not working for neither
const [loadBackBtn, setLoadBackBtn] = useState(false);
useEffect(() => {
if (loadBackBtn) {
setLoadBackBtn(false);
return;
} else {
const stateQuery = router.query;
const { asPath } = router;
window.history.pushState(stateQuery, "", asPath);
},[router.query?.page]