How to save base64 file to the client using JavaScript? - dynamics-crm-2011

I have the gotten a certain result from the Notes tab.
The link you see inside the iframe is the name of the file.
I have the DocumentBody from the annotation in some format that looks like base64.
How do I download it?
Thanks,
Fabio

Perform a JQuery request to a URL like this
Xrm.Page.context.getServerUrl() + "XRMServices/2011/OrganizationData.svc/ActivityMimeAttachmentSet(guid'abc...')?$select=Body"
By specifying the select you will request only what you want.
Assign the result to a variable and prepend
data:application/pdf;base64,
From there you could display it inline as an HTML object or try to open it as a new window with
window.location or window.open or document.location.href

I had already the base64 documentbody string extracted like this:
function getSla() {
// Define SOAP message
var objectId;
if (typeof crmForm === "undefined") {
objectId = parent.crmForm.ObjectId;
}
else {
objectId = crmForm.ObjectId;
}
var xml =
[
"<?xml version='1.0' encoding='utf-8'?>",
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" ",
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ",
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">",
GenerateAuthenticationHeader(),
"<soap:Body>",
"<RetrieveMultiple xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>",
"<query xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' ",
"xsi:type='q1:QueryExpression'>",
"<q1:EntityName>annotation</q1:EntityName>",
"<q1:ColumnSet xsi:type='q1:AllColumns' />",
"<q1:Distinct>false</q1:Distinct><q1:Criteria><q1:FilterOperator>And</q1:FilterOperator>",
"<q1:Conditions><q1:Condition><q1:AttributeName>objectid</q1:AttributeName><q1:Operator>Equal</q1:Operator>",
"<q1:Values><q1:Value xsi:type=\"xsd:string\">",
objectId,
"</q1:Value></q1:Values></q1:Condition></q1:Conditions></q1:Criteria>",
"</query>",
"</RetrieveMultiple>",
"</soap:Body>",
"</soap:Envelope>"
].join("");
var resultXml = executeSoapRequest("RetrieveMultiple", xml);
var result = filter(resultXml.getElementsByTagName("q1:filename"), function (element) {
return /master.*sla/i.test(element.text);
});
if (result.length == 0) {
return null;
}
else {
return result[0].parentNode;
}
}
function getSlaDocumentBody(sla) {
return sla.getElementsByTagName("q1:documentbody")[0].text;
}
window.open("data:application/pdf;base64," + getSlaDocumentBody(sla));
It opened a new window with the string data:application/pdf.......... in the address bar but did nothing. I would prefer that solution indeed.
Ended up using srasmussen solution in here: http://social.microsoft.com/Forums/en/crm/thread/05134277-dd76-4fbb-8f6e-89b1a2a45af1.
var URL = serverUrl + "/userdefined/edit.aspx?etc=5&id=" + slaId;
$.get(URL, function (data) {
var WRPCTokenElement = $(data).find("[WRPCTokenUrl]");
if (WRPCTokenElement) {
var WRPCTokenUrl = WRPCTokenElement.attr("WRPCTokenUrl");
if (WRPCTokenUrl) {
URL = "/Activities/Attachment/download.aspx?AttachmentType=5&AttachmentId=" + slaId + "&IsNotesTabAttachment=undefined" + WRPCTokenUrl;
window.open(URL);
}
}
return false;
});

Related

How to return from link formatter url callback without making a hyperlink

I am using the formatter:"link" url callback to generate a hyperlink for a certain column in my Tabulator table
tabulatorTable.addColumn({
title: "Value",
field: "JSONDoc.Path.To.Property",
formatter: "link",
formatterParams: {
url: getHyperLink,
target: "_blank"
}
});
Then in my callback function:
function getHyperLink(cellComp) {
var cellData = cellComp.getData();
var propValFromJSONSource = cellData.SomeProperty;
if( propValFromJSONSource != 0) {
return "http://hostname/report/showLog.php?prop=" + propValFromJSONSource;
}
else {
// If here, I can't generate a valid link, so I want to not have a hyperlink and just show the data
return ???;
}
}
Is there anything that I can do in the else statement to return from the formatter to instruct Tabulator to not create a hyperlink?
I've tried:
return ""; // This makes the hyperlink go to "<currentURL>"
return null; // This generates a relative hyperlink to "<currentURL>/null"
return undefined; // This generates a relative hyperlink to "<currentURL>/undefined"
I suspect I might not be able to use the link formatter and will need to switch to a custom formatter callback that returns "
I also have the problem of not being able to left-click on the hyperlink (even though it appears correctly down in the status bar); I can only center click or right-click and choose "Open in new tab". I'm not sure if this a bug within Tabulator, or Chrome not understanding it for some reason, but that shall be another SO question...
For now, I'm recommending the use of a custom formatter:
tabulatorTable.addColumn({
title: "Value",
field: "JSONDoc.Path.To.Property",
formatter: getHyperLink,
});
Then have the callback return the html code for a hyperlink or just text:
function getHyperLink(cellComp, formatterParams, onRendered) {
var cellData = cellComp.getData();
var cellValue = cellComp.getValue();
var propValFromJSONSource = cellData.SomeProperty;
if( propValFromJSONSource != 0) {
var hrefString = "http://hostname/report/showLog.php?prop=" + propValFromJSONSource;
return "<a href='" + hrefString + "' target='_blank'>" + cellValue + "</a>";
}
else {
return cellValue;
}
}

How can I pass object properties to onSyndicationSuccess event while using SMF.Net.WebClient dynamically

I'm trying to create a central function for dynamic web requests.
function makeWebRequest(remoteURL, requestString, callBackFunction) {
var myWebRequest = new SMF.Net.WebClient({
url : remoteURL,
httpMethod : "POST",
requestString : requestString,
requestHeaders : [
"Content-Type: application/x-www-form-urlencoded"],
onSyndicationSuccess : callBackFunction,
onServerError : function (e) {
alert(e);
}
});
myWebRequest.run(false);
}
While calling makeWebRequest, passing a callBackFunction to it like;
var remoteURL = "http://parse.com/12/test";
var requestString = "category=news&type=world";
function callBackFunction(e) {
responseText = this.responseText;
if (responseText != null) {
parsedJSON = JSON.parse(responseText);
}
}
makeWebRequest(remoteURL,requestString,callBackFunction);
Application raises an error at line
responseText = this.responseText;
How can I pass myWebRequest itself to a function like that?
I used your codeLines. I just add a textButton to Page1, and it works fine both for Android and iOS .
In Global.js;
function makeWebRequest(remoteURL, requestString, callBackFunction) {
var myWebRequest = new SMF.Net.WebClient({
url : remoteURL,
httpMethod : "POST",
requestString : requestString,
requestHeaders : [
"Content-Type: application/x-www-form-urlencoded"],
onSyndicationSuccess : callBackFunction,
onServerError : function (e) {
alert(e);
}
});
myWebRequest.run(false);
}
var remoteURL = "http://parse.com/12/test";
var requestString = "category=news&type=world";
function callBackFunction(e) {
var responseText = this.responseText;
alert(responseText);
if (responseText != null) {
parsedJSON = JSON.parse(responseText);
}
}
function Global_Events_OnStart(e) {
changeLang(Device.language, true);
include("BC.js"); //included for future BC support. Removing is not advised.
// Comment following block for navigationbar/actionbar sample. Read the JS code file for usage.
// Also there is a part of code block in Page1, which should be copied to every page for HeaderBar usage
load("HeaderBar.js");
header = new HeaderBar();
// Uncomment following block for menu sample. Read the JS code file for usage.
/*
load("Menu.js");
/**/
}
function Global_Events_OnError(e) {
switch (e.type) {
case "Server Error":
case "Size Overflow":
alert(lang.networkError);
break;
default:
SES.Analytics.eventLog("error", JSON.stringify(e));
//change the following code for desired generic error messsage
alert({
title : lang.applicationError,
message : e.message + "\n\n*" + e.sourceURL + "\n*" + e.line + "\n*" + e.stack
});
break;
}
}
In Page1.js;
function Page1_Self_OnKeyPress(e) {
if (e.keyCode === 4) {
Application.exit();
}
}
function Page1_Self_OnShow() {
//Comment following block for removing navigationbar/actionbar sample
//Copy this code block to every page onShow
header.init(this);
header.setTitle("Page1");
header.setRightItem("RItem");
header.setLeftItem();
/**/
}
function Page1_TextButton1_OnPressed(e){
makeWebRequest(remoteURL,requestString,callBackFunction);
}
it works fine. Check your makeWebRequest function, must be on Global.js. Also define "responseText" variable with "var".

Error when trying to setTitle on new DB

I'm working on an Archiving Application with this code in it:
var arcName:String = "Archives/" + aDBName + "-Backup-" + toDay + "-" + thisTime.slice(0,5);
var server:String = appDB.getServer();
var arcDB:NotesDatabase = appDB.createCopy(server, arcName);
arcDB.setTitle("This is a Test");
but it fails at the arcDB.setTitle - the new copy of the Database is created so there is no issue to that point.
This is from the IBM Knowledge base:
var db2:NotesDatabase = db.createCopy(null, "names2");
db2.setTitle("Copy of names");
I can't see the difference between these two pieces of code.
Am I missing something?
Usually when something doesn't work with XPages that relates to database or design objects the first thing I check is the Maximum Internet Name and password Access https://stackoverflow.com/a/23045860/1187943
Or change so I do the work using sessionAsSigner or sessionAsSignerWithFullAccess
If you don't care about the effectiveUser's access to the source database, their permissions to make a copy, and their access rights to create a NotesDatabase on the target Domino server, I'd absolutely second Fredrik's suggestion to use sessionAsSigner/WithFullAccess.
Additionally, I find it's best practice to use try/catches (helps with troubleshooting and errorHandling), object testing (.isOpen() when accessing a NotesDatabase), and returning an Object that can be read by the calling function.
Here's some example code that might help:
var copyNotesDatabase = function(dbName) {
var isSuccessful = true;
var responseMessage = "";
try {
//set appDB using dbName from function arguments
var appDB = session.getDatabase(session.getServerName(),dbName);
//var appDB = sessionAsSigner.getDatabase(session.getServerName(),"sourceDb.nsf");
//var appDB = sessionAsSignerWithFullAccess.getDatabase(session.getServerName(),"sourceDb.nsf");
if(appDB.isOpen()) {
var arcName:String = "Archives/" + aDBName + "-Backup-" + toDay + "-" + thisTime.slice(0,5);
var server:String = appDB.getServer();
//arcDB will be created based on appDB permissions, ie effectiveUser, or sessionAsSigner, etc.
var arcDB:NotesDatabase = appDB.createCopy(server, arcName);
if(arcDB.isOpen()) {
arcDB.setTitle("This is a Test");
responseMessage = "Successfully copied NotesDatabase!"
} else {
isSuccessful = false;
responseMessage = "Unable to open copied NotesDatabase.";
}
} else {
isSuccessful = false;
responseMessage = "Unable to open source NotesDatabase.";
}
} catch(e) {
print("Error from SSJS: " + e);
isSuccessful = false;
responseMessage = e;
}
return { status : isSuccessful, message : responseMessage };
}
With this function, you could do something like this:
function makeCopy(appName) {
var fObj = copyNotesDatabase(appName);
if(fObj.status) {
return "Successfully copied " + appName;
} else {
return fObj.message;
}
}
... at the very least, using a try/catch and returning your error will at least tell you why your current code isn't working. Hope this helps!

Need if-else advice in actionscript3

function clickButtonHandler(event:MouseEvent):void
{
var message:Object = new Object();
message.text = txtMessage.text;
message.userName = txtUser.text;
//Posts to this swf
showMessage(message);
//Posts to ALL OTHER swf files..
group.post(message);
}
function showMessage(message:Object):void
{
output_txt.appendText(message.userName+": "+message.text + "\n");
}
function jsalertwindow(event:MouseEvent):void
{
var alert:URLRequest = new URLRequest("javascript:alert('Please enter your User name')");
navigateToURL(alert, "_self");
}
As you can see there are two function which are contain mouseevent. I want to send those function with an if-else statement. If user write something in text input component which name is txtUser and,
send_btn.addEventListener(MouseEvent.CLICK, clickButtonHandler);
will work, else(if the user forget writing anything)
send_btn.addEventListener(MouseEvent.CLICK, jsalertwindow);
will work.
And one more question should i use MouseEvent.CLICK or MouseEvent.MOUSE_DOWN? Thanks for your advice.
Assign a single handler to the button click (MouseEvent.CLICK is the right event to use) and check the field is populated in the handler:
function clickButtonHandler(event:MouseEvent):void
{
var message:Object = new Object();
// Check the field is populated
if (txtUser.text != "")
{
message.text = txtMessage.text;
message.userName = txtUser.text;
showMessage(message);
//Posts to ALL OTHER swf files..
group.post(message);
}
else
{
// Nothing in the input field, show the alert
showAlert();
}
}
function showMessage(message:Object):void
{
output_txt.appendText(message.userName+": "+message.text + "\n");
}
function showAlert():void
{
var alert:URLRequest = new URLRequest("javascript:alert('Please enter your User name')");
navigateToURL(alert, "_self");
}

Using getDocumentByKey: 'Undefined' is not a function

I'm trying to enter a notes document by using the getDocumentByUNID function. Running the following code snipped outputs an error:
var unid = (function() {
for (var x in e.row.children) {
if (e.row.children[x].content == "id") {
return e.row.children[x].text;
}
}
})();
if (!unid) {
YN.exception("Function displayGeraet: Document ID could not be found!");
} else {
var Geraete_db = app.notes_db_geraete;
YN.log("Unid: "+unid); //Output: Unid: 22EC92ED5AF33138C1257BA30053E753
YN.log("URL: "+Geraete_db.baseURL); //Output: URL: http://MT04.wd.isernhagen/HKMT/Ticket/Geraete.nsf
var Geraete_doc = Geraete_db.getDocumentbyUNID(unid); //EXCEPTION: openGeraet, TypeError: 'undefined' is not a function (evaluating 'db.getDocumentbyUNID(unid)')
Any suggestions what I'm missing?
do you have "Geraete_db.getDocumentByUNID(unid)" with "By" in uppercase or with lower case as in your code sample?
It should be getDocumentByUNID().

Resources