I would like to insert a watermark into a Word document using Office.js. I am able to insert the watermark DRAFT using the sample code from: https://github.com/OfficeDev/Word-Add-in-JS-Watermark/blob/master/WatermarksManagerWeb/Home.js. The sample code places the watermark all on pages.
I am interested in a simpler solution than the one below that places the watermark only on the first page. Thank you.
(function () {
"use strict";
var messageBanner;
// The initialize function must be run each time a new page is loaded.
Office.initialize = function (reason) {
$(document).ready(function () {
$('#createWM').click(insertWaterMark);
$('#deleteWM').click(removeWM);
$('#txtWM').val("DRAFT");
});
};
function insertWaterMark() {
Word.run(function (ctx) {
var mySections = ctx.document.sections;
ctx.load(mySections);
// ctx.document.body.insertOoxml(mywatermark, "end");
return ctx.sync().then(function () {
var myWatermark = getWM($('#txtWM').val());
var myHeader = mySections.items[0].getHeader("primary");
var myRange = myHeader.insertOoxml(myWatermark, "replace");
var myCC = myRange.insertContentControl();
myCC.title = "myTempCC";
myCC.appearance = "hidden";
return ctx.sync();
});
}).catch(function (e) {
app.showNotification(e.message, e.description);
});
}
function getWM(text) {
var mywatermark = "<?xml version=\"1.0\" standalone=\"yes\"?>\r\n<?mso-application progid=\"Word.Document\"?>\r\n<pkg:package xmlns:pkg=\"http://schemas.microsoft.com/office/2006/xmlPackage\"> ... THE REST OF THE OPENXML content for watermark ...</pkg:package>\r\n";
return (mywatermark.replace("CONFIDENTIAL", text));
}
Update: I think I have an idea how to get the watermark on the first page. I implemented the solution, but it doesn't show the watermark. Please look at my code and let me know if you see anything wrong with it.
var mySections = ctx.document.sections;
ctx.load(mySections);
return ctx.sync().then(function () {
var myWatermark = getWM("DRAFT");
var myHeader = mySections.items[0].getHeader(Word.HeaderFooterType.firstPage);
mySections.items[0].headerFooterFirstPageDifferent = true;
var myRange = myHeader.insertOoxml(myWatermark, "replace");
var myCC = myRange.insertContentControl();
myCC.title = "myTempCC";
myCC.appearance = "hidden";
return ctx.sync();
I looked in the documentation, here on stackoverflow, on github and in several places but I couldn't find any solution that would help me to insert a watermark in the page header.
But after a few days of difficulty, I was testing all possible methods and combinations of use until I managed to understand how to insert the watermark. And it's simpler than I thought. Too bad this isn't in Microsoft Docs.
return Word.run( (context) => {
context.document.sections.getFirst().getHeader().insertParagraph('WaterMark', Word.InsertLocation.start);
context.sync();
});
I figured out how to insert a real watermark into the body of a document.
private async insertWatermark(): void {
await Word.run(async (context) => {
const paragraphs = context.document.sections.getFirst().getHeader(Word.HeaderFooterType.primary).paragraphs;
paragraphs.load("$none");
await context.sync();
const newParagraph = paragraphs.getLastOrNullObject();
let contentControl = newParagraph.insertContentControl();
contentControl.insertOoxml(this.addWatermarkText("My Watermark Text"), Word.InsertLocation.end);
await context.sync();
}
private addWatermarkText(text: string = "My Watermark"): string {
const watermark: string = 'Watermark Content HERE';
return watermark.replace("WATERMARK", text);
}
Get Watermark content in this link for replace this code snippet 'Watermark Content HERE'
Related
i want to write some condition for protractor autotest.
Example:
if (currentUrl == comparedUrl) {// do first;}
else {// do second;}
For this one i tried to use code:
var currentUrl = browser.getCurrentUrl().then( function( url ) {
return url;
});
console.log("current url = " + currentUrl);
i get response:
current url = ManagedPromise::122 {[[PromiseStatus]]: "pending"};
but next code works well:
var currentUrl = browser.getCurrentUrl().then( function( url ) {
console.log(url);
});
I don't understand why, and that one isn't what i need. I need to get a string of the URL.
Promises and browser.getCurrentUrl()
Please review how promises work. In the following example:
var currentUrl = browser.getCurrentUrl().then( function( url ) {
return url;
});
console.log("current url = " + currentUrl);
browser.getCurrentUrl() and the following chained callback both have the same return type Promise<string>. This means that currentUrl does not have a value of string. You will either need to continue chaining your thenables or change this to async / await.
Setting async / await
You'll need to add the SELENIUM_PROMISE_MANAGER: false in your Protractor configuration. Then in your test you'll be able to await Promises.
it('should do something', async () => {
const currentUrl = await browser.getCurrentUrl(); // promise is awaited, result is a string.
console.log(`current url = ${currentUrl}`);
});
if you just want to compare the current url with comparedUrl then you can just use browser.getCurrentUrl();
var currentUrl = browser.getCurrentUrl();
if(currentUrl === comparedUrl) {
//do first
} else {
//do second
}
Use async await
(async()=>{
var url = await browser.getCurrentUrl();
console.log(url)
})()
await will force browser.getCurrentUrl() to return a promise. Using async await you can avoid then callbacks.
Have you tried something like this?
var urlText = '';
var currentUrl = browser.getCurrentUrl()
.then(function(text){
urlText = text;
if (urlText == comparedUrl) {
// do first;
}
else {
// do second;
}
});
Hope it helps.
I have an Office Addin and am trying to update the title of the document on desktop. i have tried 2 diffrent ways and none of them works on hte desktop. It works fine on word online but not on the desktop.
Word.run(async (context) => {
var newTitle = document.getElementById("inputTitle") as HTMLInputElement;
console.log(newTitle.value);
context.document.properties.title = newTitle.value;
});
This code works online but not on the desktop. I have also tried doing doing it in this way.
Office.context.document.customXmlParts.getByNamespaceAsync("http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
function (resultCore) {
var xmlPart = resultCore.value[0];
xmlPart.getNodesAsync('*/*', function (nodeResult) {
for (var i = 0; i < nodeResult.value.length; i++) {
var node = nodeResult.value[i];
console.log("BaseName: ")
console.log(node.baseName);
if (node.baseName === "title") {
var newTitle = document.getElementById("inputTitle") as HTMLInputElement;
console.log("title that you entered: " + newTitle.value);
console.log(node);
node.setNodeValueAsync(newTitle.value, { asyncContext: "StateNormal" }, function (data) { });
}
}
});
});
Does anyone know why it doesn't work or have some other solution to my problem?
The following code works for me, including on desktop. Note that you have to await the Word.run. Also, you have to load the title and then sync to make sure you have changed the title on the actual document and not merely in the proxy object in your task pane code.
await Word.run(async (context) => {
var newTitle = document.getElementById("inputTitle") as HTMLInputElement;
console.log(newTitle.value);
context.document.properties.title = newTitle.value;
const myProperties = context.document.properties.load("title");
await context.sync();
console.log(myProperties.title);
});
I need some help with Javascript to get fancybox working with SCP. The following solution has not worked for me although I'm aware I'm missing some fundamental code. The first product image works perfectly opening the fancybox lightbox but once you select from the configurable dropdowns it changes the image which then does not call the lightbox and opens in the browser.
SCP advice is:
To fix, it's often just a matter of editing the showFullImageDiv function in the scp_product_extension.js file: Change evalScripts to true if it's not already, and possibly you'll also need to remove the code which exists in a few places which looks like: product_zoom = new Product.Zoom('image', 'track', 'handle', 'zoom_in', 'zoom_out', 'track_hint');
I tried this but it's not just a simple matter of removing "product_zoom..." my understanding is that fancybox needs to be called replace this line of code.
Original:
Product.Config.prototype.showFullImageDiv = function(productId, parentId) {
var imgUrl = this.config.ajaxBaseUrl + "image/?id=" + productId + '&pid=' + parentId;
var prodForm = $('product_addtocart_form');
var destElement = false;
var defaultZoomer = this.config.imageZoomer;
prodForm.select('div.product-img-box').each(function(el) {
destElement = el;
});
if(productId) {
new Ajax.Updater(destElement, imgUrl, {
method: 'get',
evalScripts: true,
onComplete: function() {
//Product.Zoom needs the *image* (not just the html source from the ajax)
//to have loaded before it works, hence image object and onload handler
if ($('image')){
var imgObj = new Image();
imgObj.src = $('image').src;
imgObj.onload = function() {product_zoom = new Product.Zoom('image', 'track', 'handle', 'zoom_in', 'zoom_out', 'track_hint'); };
} else {
destElement.innerHTML = defaultZoomer;
product_zoom = new Product.Zoom('image', 'track', 'handle', 'zoom_in', 'zoom_out', 'track_hint')
}
}
});
} else {
destElement.innerHTML = defaultZoomer;
product_zoom = new Product.Zoom('image', 'track', 'handle', 'zoom_in', 'zoom_out', 'track_hint');
}
};
I know I need to call fancybox in the below locations but not sure how to go about it. From what I understand fancybox is called on pageload so not sure imgObj.onload will even work?
Product.Config.prototype.showFullImageDiv = function(productId, parentId) {
var imgUrl = this.config.ajaxBaseUrl + "image/?id=" + productId + '&pid=' + parentId;
var prodForm = $('product_addtocart_form');
var destElement = false;
var defaultZoomer = this.config.imageZoomer;
prodForm.select('div.product-img-box').each(function(el) {
destElement = el;
});
if(productId) {
new Ajax.Updater(destElement, imgUrl, {
method: 'get',
evalScripts: true,
onComplete: function() {
//Product.Zoom needs the *image* (not just the html source from the ajax)
//to have loaded before it works, hence image object and onload handler
if ($('image')){
var imgObj = new Image();
imgObj.src = $('image').src;
imgObj.onload = CALL FANCYBOX
} else {
destElement.innerHTML = defaultZoomer;
CALL FANCYBOX
}
}
});
} else {
destElement.innerHTML = defaultZoomer;
CALL FANCYBOX
}
};
Unfortunately my javascript is very basic and any help on what I need to add would be gratefully received. I found a few posts with the same issue but no solution.
Thanks
I am using Recorder.js, which allows you to display an audio recording like so
recorder.exportWAV(function(blob) {
var url = URL.createObjectURL(blob);
var au = document.createElement('audio');
au.controls = true;
au.src = url;
}
But how can I save the blob to the database? Assuming I have a Recordings collection:
recorder.exportWAV(function(blob) {
Recordings.insert({data: blob});
}
will only store this
{data: { "type" : "audio/wav", "size" : 704556 }}
which does not have the actual content.
After watching the file upload episode from eventedmind.com, it turns out the way to do it is to use the FileReader to read a blob as ArrayBuffer, which is then converted to Uint8Array to be stored in mongo:
var BinaryFileReader = {
read: function(file, callback){
var reader = new FileReader;
var fileInfo = {
name: file.name,
type: file.type,
size: file.size,
file: null
}
reader.onload = function(){
fileInfo.file = new Uint8Array(reader.result);
callback(null, fileInfo);
}
reader.onerror = function(){
callback(reader.error);
}
reader.readAsArrayBuffer(file);
}
}
The exportWAV callback is then
recorder.exportWAV(function(blob) {
BinaryFileReader.read(blob, function(err, fileInfo){
Recordings.insert(fileInfo)
});
});
Then I can display one of my recordings by:
Deps.autorun(function(){
var rec = Recordings.findOne();
if (rec){
var au = document.createElement('audio');
au.controls = true;
var blob = new Blob([rec.file],{type: rec.type});
au.src = URL.createObjectURL(blob);
document.getElementById("recordingslist").appendChild(au);
}
})
I don't know if the previous snippet works in other browsers, but this may:
var base64Data = btoa(String.fromCharCode.apply(null, rec.file))
var au = document.createElement('audio');
au.controls = true;
au.src = "data:"+rec.type+";base64,"+base64Data
Just in case, did you notice this line in their example
Make sure you are using a recent version of Google Chrome, at the
moment this only works with Google Chrome Canary.
I will soon need to look into this for my own project, hope you get it running.
Heres the jsfiddle, jsfiddle.net/kqreJ
So I was using .bind no problem for this function but then I loaded more updates to the page and found out that .bind doesn't work for content imported to the page but just for content already on the page! Great!
So I switched it up to .delegate which is pretty cool but now I can't figure out how to .bind .unbind my function the way it was???
Function using .bind which worked perfect... except didn't work on ajax content.. :(
$('.open').bind("mouseup",function(event) {
var $this = $(this), handler = arguments.callee;
$this.unbind('mouseup', handler);
var id = $(this).attr("id");
var create = 'nope';
var regex = /\d+$/,
statusId = $('#maindiv .open').toArray().map(function(e){
return parseInt(e.id.match(regex));
});
var divsToCreate = [ parseInt(id) ];
$.each(divsToCreate, function(i,e)
{
if ( $.inArray(e, statusId) == -1 ) {
create = 'yup';
}
});
if( create == 'yup' ) {
if(id) {
$.ajax({
type: "POST",
url: "../includes/open.php",
data: "post="+ id,
cache: false,
success: function(html) {
$('.open').html(html);
$this.click(handler);
}
});
}
}
});
New function using .delegate that is not binded and creates multiple instances?
$('#maindiv').delegate("span.open", "mouseup",function(event) {
var $this = $(this), handler = arguments.callee;
$this.unbind('mouseup', handler);
var id = $(this).attr("id");
var create = 'nope';
var regex = /\d+$/,
statusId = $('#maindiv .open').toArray().map(function(e){
return parseInt(e.id.match(regex));
});
var divsToCreate = [ parseInt(id) ];
$.each(divsToCreate, function(i,e)
{
if ( $.inArray(e, statusId) == -1 ) {
create = 'yup';
}
});
if( create == 'yup' ) {
if(id) {
$.ajax({
type: "POST",
url: "../includes/open.php",
data: "post="+ id,
cache: false,
success: function(html) {
$('.open').html(html);
$this.click(handler);
}
});
}
}
});
I've spent hours trying to figure this out because I like learning how to do it myself but I had to break down and ask for help... getting frustrated!
I also read that when your binding and unbinding .delegate you have to put it above the ajax content? I've tried using .die() and .undelegate()... Maybe I just don't know where to place it?
Take a look at undelegate
It does to delegate what unbind does to bind.
In your case, I think it'd be something like:
$('#maindiv').undelegate("span.open", "mouseup").delegate("span.open", "mouseup" ...
Then you can drop the $this.unbind('mouseup', handler); within the function.