append hidden content to meeting body in outlook using office js - outlook-addin

using my outlook add-in I need to add some hidden data (some metadata) to meeting body. I tried adding display:none style to html element but no luck. is there any way to achieve this?
below is my code to set body content
function addWorkspaceToItemBody(textToAppend) {
var d = $q.defer();
var item = Office.context.mailbox.item;
item.body.getTypeAsync(
function (result) {
if (result.status == Office.AsyncResultStatus.Failed){
write(result.error.message);
}
else {
// Successfully got the type of item body.
// Set data of the appropriate type in body.
if (result.value == Office.MailboxEnums.BodyType.Html) {
// Body is of HTML type.
// Specify HTML in the coercionType parameter
// of setSelectedDataAsync.
item.body.setSelectedDataAsync(
'<p style="display:none">'+textToAppend+'<\p>',
{ coercionType: Office.CoercionType.Html,
asyncContext: { var3: 1, var4: 2 } },
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Failed){
d.reject(asyncResult.error.message);
}
else {
d.resolve(asyncResult)
// Successfully set data in item body.
// Do whatever appropriate for your scenario,
// using the arguments var3 and var4 as applicable.
}
});
}
else {
// Body is of text type.
item.body.setSelectedDataAsync(
"",
{ coercionType: Office.CoercionType.Text,
asyncContext: { var3: 1, var4: 2 } },
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Failed){
d.reject(asyncResult.error.message);
}
else {
d.resolve(asyncResult)
// Successfully set data in item body.
// Do whatever appropriate for your scenario,
// using the arguments var3 and var4 as applicable.
}
});
}
}
});
return d.promise;
}

Below is an example to insert hidden content using the following code. The content is hidden in Outlook 2016, OWA, and Outlook for Android. It may still show up if the content is viewed as plain text in other email clients.
var content =
"<!--[if !mso 9]><!-->"+
'<div class="hidden" style="display:none;max-height:0px;overflow:hidden;">'+
"CONTENT HERE THAT YOU WANT TO HIDE"+
"</div>"+
"<!--<![endif]-->";
Office.context.mailbox.item.body.setSelectedDataAsync("Hello World! " + content, function (asyncResult) {
if (asyncResult.status == "failed") {
console.log("Action failed with error: " + asyncResult.error.message);
}
});
Source

Related

How to get data using Add-in program from Office document without metadata(i.e. creation time)?

There's a function which retrieves document of PDF format byte by byte:
Office.initialize = function (reason) {
$(document).ready(function () {
// If not using Word 2016
if (!Office.context.requirements.isSetSupported('WordApi', '1.1')) {
$('#hash-button-text').text("Not supported!");
return;
}
//$('#hash-button').click(calculate_hash);
$('#btn').click(getFile);
});
};
function getFile() {
Office.context.document.getFileAsync(Office.FileType.Pdf, { sliceSize: 99 },
function (result) {
if (result.status == "succeeded") {
var file = result.value;
var sliceCount = file.sliceCount;
var slicesReceived = 0, gotAllSlices = true, docdataSlices = [];
getSliceAsync(file, 0, sliceCount, gotAllSlices, docdataSlices, slicesReceived);
}
else {
console.log("Error");
}
}
);
}
function getSliceAsync(file, nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived) {
file.getSliceAsync(nextSlice, function (sliceResult) {
if (sliceResult.status == "succeeded") {
if (!gotAllSlices) { // Failed to get all slices, no need to continue.
return;
}
docdataSlices[sliceResult.value.index] = sliceResult.value.data;
if (++slicesReceived == sliceCount) {
file.closeAsync();
console.log("Done: ", docdataSlices);
}
else {
getSliceAsync(file, ++nextSlice, sliceCount, gotAllSlices, docdataSlices, slicesReceived);
}
}
else {
gotAllSlices = false;
file.closeAsync();
console.log("getSliceAsync Error:", sliceResult.error.message);
}
});
}
So, close to ~1800 byte there are bytes like "CreationDate(D:20190218150353+02'00..." which are unnecessary in our case.
It retrieves the whole PDF file which consists meta, but is it possible to get it without it?
Best regards
The document.getFileAsync method will always return the entire document (including metadata); it's not possible to make it return anything less than the entire document.

setAsync returns success status but not inserting data in MAC installed outlook

here I am implementing an email tracking system using image insertion , and i used 'Office.context.mailbox.item.body.setAsync' office API , everywhere it is working but not in installed MAC outlook though it returns 'success' in asyncResult.status.Please help me out.
Also, as a reference you can try the below mentioned code snippet:
var htmlData = '<img src=\"https://www.w3schools.com/css/paris.jpg\">';
Office.context.mailbox.item.body.setAsync(
htmlData,
{coercionType: "html"},
function (asyncResult) {
if (asyncResult.status == "failed") {
console.log("Action failed with error: " + asyncResult.error.message);
}
else {
console.log("Successfully set body text");
}
}
);
/* ReadWriteItem or ReadWriteMailbox */
/* Set body content */
Office.context.mailbox.item.body.setAsync(
'<img src=\"https://www.w3schools.com/css/paris.jpg\">',
{coercionType: "html"},
function (asyncResult) {
if (asyncResult.status == "failed") {
console.log("Action failed with error: " + asyncResult.error.message);
} else {
console.log("Successfully set body text");
}
});
I used above code and it worked in 15.40

How to call to external function in axios.spread function in VueJS?

I can't call any external functions inside an axios promise. My error is
[Uncaught (in promise) TypeError: this.showNotification is not a function]
showNotification is an external function inside mixin but i can't call it in userCompInfo function
var mixin = {
methods: {
//function to get all user info
userInfo:function(){
//alert(localStorage.getItem("sessionKey"))
if(localStorage.getItem("sessionKey")==null)
session = "null";
else
session= localStorage.getItem("sessionKey");
return axios.post("/api/user/info",{
user_id:localStorage.getItem("userId"),
session_key:session
});
},
//function to get all competition info
compInfo:function()
{ //calling API competition info to get the avaliable competition for now
return axios.post("/api/competition/info",{
lang:source.lang
});
},
userCompInfo:function()
{
axios.all([this.userInfo(),this.compInfo()])
.then(axios.spread(function (user, comp){
if(comp.data.result.errorcode == 0)
{
source.competition = comp.data.competiton_detail;
}
//set the user id in local storage
localStorage.setItem("userId",user.data.user_info.user_id);
//check on session key to save it in local storage
if(user.data.user_info.session_key != "") // for testing
localStorage.setItem("sessionKey",user.data.user_info.session_key);
// get user data successfuly
if(user.data.result.errorcode == 0)
{ //set response data in user
source.user = user.data.user_info;
//to set this user status
this.renderUserInfo();
///////////
//source.competition.is_active=1;
//check on user status to show notification
if(source.user.vip && source.user.suspended)
{
this.showNotification(context.suspended_vip.title+" "+source.user.msisdn, context.suspended_vip.body,["btn_notifi_ok"]);
}
//check if this valid competition is active or not to show notification according to it and to user status
if(source.competition.is_active==1)
{
if(source.user.registered && newUser==1)
{
this.showNotification(context.registered_firstTime.title, context.registered_firstTime.body, ["btn_notifi_start_play"]);
}
else if(source.user.free && source.user.newFreeUser)
{
this.showNotification(context.freeUser_firstTime.title, context.freeUser_firstTime.body, ["btn_notifi_start_play"]);
}
}
}
}));
},
// function to show notification modal
showNotification:function(title, body, buttons)
{
//to hide all modal buttons first
$("#notification").find(".btn").hide();
//set the modal title
$("#notification_title").html(title);
//set the modal body
$("#notification_body").html(body);
//for on buttons array to show all buttons that we want
for(i=0;i<buttons.length;i++)
{
$("#notification").find("#"+buttons[i]).show();
}
//to display modal
$("#notification").modal("show");
},
//function to show the current user statue VIP, registered,free or suspended
renderUserInfo:function()
{ // intialize all flags of user status to false
source.user.vip = false;
source.user.registered = false;
source.user.free = false;
//check on user mode and set the according flag to it to true
if(source.user.sub_mode == "vip")
{
source.user.vip = true;
}
else if(source.user.sub_mode == "sub")
{
source.user.registered = true;
}
else
{
source.user.free = true;
}
},}}
This is a very common mistake. this in userCompInfo doesn't refer to the Vue because of they way you have written the callback.
In your code, make this change.
userCompInfo:function()
{
axios.all([this.userInfo(),this.compInfo()])
.then(axios.spread(function (user, comp){
// a bunch of code...
}.bind(this)));
},
Or
userCompInfo:function()
{
let self = this;
axios.all([this.userInfo(),this.compInfo()])
.then(axios.spread(function (user, comp){
// a bunch of code...
self.showNotification(...)
// some more code...
}));
},
See How to access the correct this inside a callback?

How to delete multiple users from a group

Not sure why facebook refered me here but anyhow, let me ask the question. I have a group on facebook with over 4000 members. I want to delete old members that are not active on the group anymore. Is there a way to select multiple users for deletion?
How to get a list of ID's of your facebook group to avoid removal of active users, it's used to reduce as well a group from 10.000 to 5000 members as well as removal of not active members or old members "You will risk removing some few viewers of the group" "remember to open all comments while you browse down the page":
You will need to have Notepad++ for this process:
After you save the HTML. Remove all information before of document:
"div id=contentArea" to
"div id=bottomContent"
to avoid using messenger ID's,
somehow script will run problems if you have ID's by blocked users.
As well as a different example of how to parse as well as text and code out of HTML. And a range of numbers if they are with 2 digits up to 30.
You can try this to purge the list of member_id= and with them along with numbers from 2 to up to 30 digits long. Making sure only numbers and whole "member_id=12456" or "member_id=12" is written to file. Later you can replace out the member_id= with blanking it out. Then copy the whole list to a duplicate scanner or remove duplicates. And have all unique ID's. And then use it in the Java code below.
"This is used to purge all Facebook user ID's by a group out of a single HTML file after you saved it scrolling down the group"
Find: (member_id=\d{2,30})|.
Replace: $1
You should use the "Regular Expression" and ". matches newline" on above code.
Second use the Extended Mode on this mode:
Find: member_id=
Replace: \n
That will make new lines and with an easy way to remove all Fx0 in all lines to manually remove all the extra characters that come in buggy Notepad++
Then you can easily as well then remove all duplicates. Connect all lines into one single space between. The option was to use this tool which aligns the whole text with one space between each ID: https://www.tracemyip.org/tools/remove-duplicate-words-in-text/
As well then again "use Normal option in Notepad++":
Find: "ONE SPACE"
Replace ','
Remember to add ' to beginning and end
Then you can copy the whole line into your java edit and then remove all members who are not active. If you though use a whole scrolled down HTML of a page. ['21','234','124234'] <-- remember right characters from beginning. Extra secure would be to add your ID's to the beginning.
You put your code into this line:
var excludedFbIds = ['1234','11223344']; // make sure each id is a string!
The facebook group removal java code is on the user that as well posted to this solution.
var deleteAllGroupMembers = (function () {
var deleteAllGroupMembers = {};
// the facebook ids of the users that will not be removed.
// IMPORTANT: bobby.leopold.5,LukeBryannNuttTx!
var excludedFbIds = ['1234','11223344']; // make sure each id is a string!
var usersToDeleteQueue = [];
var scriptEnabled = false;
var processing = false;
deleteAllGroupMembers.start = function() {
scriptEnabled = true;
deleteAll();
};
deleteAllGroupMembers.stop = function() {
scriptEnabled = false;
};
function deleteAll() {
if (scriptEnabled) {
queueMembersToDelete();
processQueue();
}
}
function queueMembersToDelete() {
var adminActions = document.getElementsByClassName('adminActions');
console.log(excludedFbIds);
for(var i=0; i<adminActions.length; i++) {
var gearWheelIconDiv = adminActions[i];
var hyperlinksInAdminDialog = gearWheelIconDiv.getElementsByTagName('a');
var fbMemberId = gearWheelIconDiv.parentNode.parentNode.id.replace('member_','');
var fbMemberName = getTextFromElement(gearWheelIconDiv.parentNode.parentNode.getElementsByClassName('fcb')[0]);
if (excludedFbIds.indexOf(fbMemberId) != -1) {
console.log("SKIPPING "+fbMemberName+' ('+fbMemberId+')');
continue;
} else {
usersToDeleteQueue.push({'memberId': fbMemberId, 'gearWheelIconDiv': gearWheelIconDiv});
}
}
}
function processQueue() {
if (!scriptEnabled) {
return;
}
if (usersToDeleteQueue.length > 0) {
removeNext();
setTimeout(function(){
processQueue();
},1000);
} else {
getMore();
}
}
function removeNext() {
if (!scriptEnabled) {
return;
}
if (usersToDeleteQueue.length > 0) {
var nextElement = usersToDeleteQueue.pop();
removeMember(nextElement.memberId, nextElement.gearWheelIconDiv);
}
}
function removeMember(memberId, gearWheelIconDiv) {
if (processing) {
return;
}
var gearWheelHref = gearWheelIconDiv.getElementsByTagName('a')[0];
gearWheelHref.click();
processing = true;
setTimeout(function(){
var popupRef = gearWheelHref.id;
var popupDiv = getElementByAttribute('data-ownerid',popupRef);
var popupLinks = popupDiv.getElementsByTagName('a');
for(var j=0; j<popupLinks.length; j++) {
if (popupLinks[j].getAttribute('href').indexOf('remove.php') !== -1) {
// this is the remove link
popupLinks[j].click();
setTimeout(function(){
var confirmButton = document.getElementsByClassName('layerConfirm uiOverlayButton selected')[0];
var errorDialog = getElementByAttribute('data-reactid','.4.0');
if (confirmButton != null) {
if (canClick(confirmButton)) {
confirmButton.click();
} else {
console.log('This should not happen memberid: '+memberId);
5/0;
console.log(gearWheelIconDiv);
}
}
if (errorDialog != null) {
console.log("Error while removing member "+memberId);
errorDialog.getElementsByClassName('selected layerCancel autofocus')[0].click();
}
processing = false;
},700);
continue;
}
}
},500);
}
function canClick(el) {
return (typeof el != 'undefined') && (typeof el.click != 'undefined');
}
function getMore() {
processing = true;
more = document.getElementsByClassName("pam uiBoxLightblue uiMorePagerPrimary");
if (typeof more != 'undefined' && canClick(more[0])) {
more[0].click();
setTimeout(function(){
deleteAll();
processing = false;
}, 2000);
} else {
deleteAllGroupMembers.stop();
}
}
function getTextFromElement(element) {
var text = element.textContent;
return text;
}
function getElementByAttribute(attr, value, root) {
root = root || document.body;
if(root.hasAttribute(attr) && root.getAttribute(attr) == value) {
return root;
}
var children = root.children,
element;
for(var i = children.length; i--; ) {
element = getElementByAttribute(attr, value, children[i]);
if(element) {
return element;
}
}
return null;
}
return deleteAllGroupMembers;
})();
deleteAllGroupMembers.start();
// stop the script by entering this in the console: deleteAllGroupMembers.stop();
Use this in Chrome or Firefox Javascript control panel.

BlackBerry 10 Cascades: How do I load data into a DropDown?

I have managed to load data from a remote Json web service into a QML ListView, but there doesn't seem to be any such thing for the DropDown control.
Does someone have an example or an alternative method to accomplish a DropDown bound to attachedObjects data sources in Cascades?
I have an alternate method for you, Do note that I have used google's web service here for demonstration purpose, you need to replace it with your url & parse response according to that.
import bb.cascades 1.0
Page {
attachedObjects: [
ComponentDefinition {
id: optionControlDefinition
Option {
}
}
]
function getData() {
var request = new XMLHttpRequest()
request.onreadystatechange = function() {
if (request.readyState == 4) {
var response = request.responseText
response = JSON.parse(response)
var addressComponents = response.results[0].address_components
for (var i = 0; i < addressComponents.length; i ++) {
var option = optionControlDefinition.createObject();
option.text = addressComponents[i].long_name
dropDown.add(option)
}
}
}
// I have used goole's web service url, you can replace with your url
request.open("GET", "http://maps.googleapis.com/maps/api/geocode/json?address=" + "Ahmedabad" + "&sensor=false", true)
request.send()
}
Container {
DropDown {
id: dropDown
}
Button {
onClicked: getData()
}
}
}
Hope this helps.