Office.js How to apply a character style to selected word - javascript

Apologies - new to Javascript and Office.js But it's time to convert my .NET formatting ribbons over to be cross platform. A bit of a learning curve.
I use this function that I found the Addin tutorial, to successfully apply a paragraph style, but I've tried tweaking it (see below) and they while I have learned that it's important to completely shut down the addin, exit out of word and go back in and reload before testing changes (very tedious), it still applies to character style to the entire paragraph. Grr
function applyemphasisstyle() {
Word.run(function (context) {
var pars = context.document.getSelection().paragraphs;
pars.load();
return context.sync().then(function () {
for (var i = 0; i < pars.items.length; i++) {
pars.items[i].style = "Emphasis";
}
return context.sync();
})
}) //needed for Stack overflow
.catch(function (error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
}
I've tried changing:
var pars = context.document.getSelection().paragraphs;
to
var pars = context.document.getSelection().getTextRanges;
I've tried just removing ".paragraphs"
I've tried changing ".paragraphs" to ".words" etc
same result - applies the style, but the entire paragraph, not the selected word.
Thanks for any help you can provide!

This code works for me. Since you are selecting a single word, there's nothing to loop through and since you are writing to the style property, instead of reading it, there's no need to load the text object.
return Word.run(function(context) {
var selectedText = context.document.getSelection();
return context.sync()
.then(function () {
selectedText.style = "Emphasis";
})
});
I recommend that you use the Script Lab tool to work out the logic of your script.

Related

Gulp- Make sure file has comments in the beginning

I have multiple javascript files in a folder and I want to make sure that every file has comment in the beginning (that will explain the summary of file).
/*
This file will......
*/
function test () {
....
}
So is this possible using gulp-contains or something else?
I think this would be enough just to make sure if start of a file is the comment initial characters (/*)
gulp.src('./file.js')
.pipe(map(function(file, callback) {
var startWithComment = file.contents.toString().replace(/\n|\r/g, "").trim().startsWith("/*");
if (startWithComment){
// DO YOUR CHORES
}
}))
Another approach is to split the initial text to make sure if it is a valid multi-line comment.
function startsWithValidMultiLineComment(str){
try{
return str.replace(/\n|\r/g, "").trim().split("/*")[1].split("*/")[1].length > 0
} catch (e){
return false;
}
}
Following this approach str.split("/*")[1].split("*/")[0] would be your comment text
By using the regex provided by #Sajjad in previous answer. I have managed to achieve my goal. I have used gulp-if and gulp-fail instead (I find it more flexible).
Here is how I do that:
var condition = function (file) {
sFile = require('path').parse(file.path).name;
var startWithComment = file.contents.toString().replace(/\n|\r/g, "").trim().startsWith("/*");
return (!startWithComment);
}
gulp.task('taskName',
function() {
gulp.src('files/*.js')
.pipe(gulpIf(condition, fail(function () {
var message = 'Some message';
return message;
})));
});

How to check when a comment is marked as done in Word Online? Javascript API for Word Add-In

I'm trying to manipulate a Word Online documents' comments with an Add-In, and to do that I'm using the getOoxml() function to directly read/modify the xml.
However I noticed that even though I can access the comments and its contents through the given XML, I can't seem to find a tag/attribute that tells me whether the comment has been marked as done or not.
Even though my target platform is Word Online, I unzipped a local Word document(.docx) to see what it does behind-the-scenes, and realized that Word has a separate document for the "done" property called "commentsExtended.xml". This is distinct from the "comments.xml" where the comments are stored.
This is the Add-In code I use to do a simple search in the XML returned as a string by getOoxml() :
Word.run(function (context) {
var properties = context.document.body.getOoxml();
return context.sync().then(function () {
let xmlString = properties.value;
let searchPositions = [];
let curIndex = 0;
let startIndex = 0;
while((curIndex = xmlString.indexOf("done", startIndex)) > -1) {
searchPositions.push(curIndex);
startIndex = curIndex + 1;
}
console.log(searchPositions);
});
})
.catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
This is the content stored in "commentsExtended.xml" that I can't seem to find in getOoxml()'s return value:
<w15:commentsEx mc:Ignorable="w15" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml">
<w15:commentEx w15:done="1" w15:paraId="1930ECCA" />
<w15:commentEx w15:done="0" w15:paraId="0B31B8E3" />
</w15:commentsEx>
The XML returned by getOoxml() in Word Online doesn't seem to include this information. Is there a way to obtain this information about a comment's "done" state within a Word Add-In?
Edit: My target version is 2016.

FileSaver.js Chrome Issue, Multiple documents

I'm using Chrome v67 and FileSaver.js.
This code works in FF & Edge but not in Chrome.
var ajaxSettings = {
url: "my/api/method",
data: JSON.stringify(myItems),
success: function (data) {
if (data) {
var dateToAppend = moment().format("YYYYMMDD-HHmmss");
createPdf("pdfDoc_" + dateToAppend + ".pdf", data[0]);
saveFile("txtDoc_" + dateToAppend + ".txt", data[1]);
//sleep(2000).then(() => {
// saveFile("txtDoc_" + dateToAppend + ".txt", data[1]);
//});
}
}
}
//function sleep(time) {
//return new Promise((resolve) => setTimeout(resolve, time));
//}
function createPdf(filename, pdfBytes) {
if (navigator.appVersion.indexOf("MSIE 9") > -1) {
window.open("data:application/pdf;base64," + encodeURIComponent(pdfBytes));
}
else {
saveFile(fileName, data);
}
}
function saveFile(fileName, data) {
var decodedByte64 = atob(data);
var byteVals = new Array(decodedByte64.length);
for (var i = 0; i < decodedByte64.length; i++) {
byteVals[i] = decodedByte64.charCodeAt(i);
}
var byte8bitArray = new Uint8Array(byteVals);
var blob = new Blob([byte8bitArray]);
saveAs(blob, fileName); //FileSaver.js
}
The result of calling the API is an array with 2 byte arrays in it.
The byte arrays are the documents.
If I run this code, as a user would, then what happens is that the first document gets "downloaded" but the second does not. Attempting to do this a second time without refreshing the page results in no documents being "downloaded". The "download" word is in quotes because it already has been downloaded, what I'm really trying to do is generate the documents from the byte arrays.
This is the strange bit ... if I open the console and place a breakpoint on the "saveFile" call and immediately hit continue when the debugger lands on the breakpoint then all is well with the world and the 2 documents get downloaded.
I initially thought it was a timing issue so I put a 2 second delay on this to see if that was it but it wasn't. The only thing I've managed to get working is the breakpoint which I'm obviously not going to be able to convince the users to start doing no matter how much I want them to.
Any help or pointers are much appreciated
You probably faced a message at the top left corner of your browser stating
https://yoursite.com wants to
Download multiple files
[Block] [Allow]
If you don't have it anymore, it's probably because you clicked on "Block".
You can manage this restriction in chrome://settings/content/automaticDownloads.

MS Word API: table values not set

Using the Office JavaScript API, I am trying to fill a selected table using the following code:
Word.run(function (context) {
var table = context.document.getSelection().parentTable;
context.load(table);
return context.sync()
.then(function () {
if (table.isNullObject == true || !table) {
console.log("selection ist not table");
errorHandler("selection is not a table");
} else {
// loop over table
for (var row = 0; row < table.values.length; row++) {
for (var column = 0; column < table.values[row].length; column++) {
console.log(table.values[row][column]);
table.values[row][column] = "Test " + row + " " + column;
}
context.sync().then(function () {
console.log("done");
}).catch(function (e) {
console.log(e);
});
}
}
});
});
The scripts runs fine, the table object exists, the values are logged and the final "done" too. But the table stays as it is - no update of the values. What am I missing?
A few comments about the code you've posted:
Checking for isNullObject on the table object like your code is doing is not effective, because the lines above that will have already thrown an error if the parentTable doesn't exist.
Error handling (catch statement) should be located immediately after the Word.run -- that way it'll catch any error that occurs inside the Word.run.
Instead of loading the entire table object like you are, you should only load the properties that you need (in this case, values and rows/items/cells/items/body).
To set a cell value, use the insertText method on the body of the cell that you want to update.
The following code sample incorporates this feedback, and should successfully update the values in your table.
Word.run(function (context) {
var table = context.document.getSelection().parentTable;
table.load("values, rows/items/cells/items/body");
return context.sync()
.then(function () {
for (var row = 0; row < table.values.length; row++) {
for (var column = 0; column < table.values[row].length; column++) {
console.log(table.values[row][column]);
table.rows.items[row].cells.items[column].body.insertText("Test " + row + " " + column, "Replace");
}
}
return context.sync()
.then (function() {
console.log("Done");
});
});
}).catch(function (e) {
console.log(e);
});
Great question #BernhardWebstudio! To explain why your specific code doesn't work is because the add-in code is invoked in a separate process from the Office Application and it must make 'requests' to actually acquire the data. This is similar to asking for attributes within a REST or OData call. (e.g. $select)
What does this mean for you? Well with a just slight alteration to your code you just need to request what properties of the table you want to load. Since you only care about the values of the table, it would be easy to do this with this type of code. If you notice I also have a commented out line that is table.load("[Property Name]"); to use the Office Apps Object model as proxy objects as well. Kim has pointed out some other really good suggestions as well. Cheers and Happy Coding!
Word.run(function (context) {
let table = context.document.getSelection().parentTable;
//table.load("values");
context.load(table, "values");
//...

Highlight HTML using Remarkable and Highlightjs

I'm having trouble getting the highlight function to execute when using Remarkable to highlight HTML code. I'm taking from the example here:
var md = new Remarkable({
html:true,
langPrefix:'lang-',
highlight: function (str, lang) {
alert('highlighting'); // never executes!
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) {}
}
try {
return hljs.highlightAuto(str).value;
} catch (err) {}
return ''; // use external default escaping
}
});
var test = md.render('<code class="lang-js">var x = 1;</code>');
See fiddle
Remarkable works when you give it text written in markdown, not HTML. It generates the HTML for you. If you wanted to write out the HTML yourself, you don't need Remarkable ;)
So, your test line should look like this:
var test = md.render('``` js\nvar x = 1;\n```\n');
(normally, text is pulled from a text area, so you don't need the "\n" in there, you would just hit enter)
Here is the working fiddle:
https://jsfiddle.net/fhz9oma1/7/

Categories