HTMLIFrameElement.contentWindow.print() from GoogleSheets is not opening print preview - google-sheets

I am using GoogleSheets to print a png/image file using HTMLService. I created a temporary Iframe element with an img tag in the modalDialog and call IFrame element's contentWindow.print() function after IFrame element and its image are loaded. (I have not set visibility:hidden attribute of IFrame element to check if image is getting loaded.)
However, I only see the printer dialog without any print preview. I am testing on Firefox. Am I missing anything?
[Updated] - I am using Googles Apps script. performPrint() is in printJsSource.html and openUrl() is in Code.gs.
Inside printJsSource.html
function performPrint(iframeElement, params) {
try {
iframeElement.focus()
// If Edge or IE, try catch with execCommand
if (Browser.isEdge() || Browser.isIE()) {
try {
iframeElement.contentWindow.document.execCommand('print', false, null)
} catch (e) {
iframeElement.contentWindow.print()
}
} else {
// Other browsers
iframeElement.contentWindow.print() // as I am using Firefox, it is coming here
}
} catch (error) {
params.onError(error)
} finally {
//cleanUp(params)
}
}
Inside Code.gs
function openUrl() {
var html = HtmlService.createHtmlOutputFromFile("printJsSource");
html.setWidth(500).setHeight(500);
var ui = SpreadsheetApp.getUi().showModalDialog(html, "Opening ..." );
}

I think there is some general confusion about the concept
First of all, function performPrint() seems to be a client-side Javascript funciton, while function openUrl() is a server-side Apps Script function.
While you did not specify either you use Google Apps Script - if you do so, function openUrl()belongs into the code.gs file and function performPrint() into printJsSource.html file
function openUrl() allows you to open a modal dialog which can show some data on the UI, e.g. your image
Do not confuse this behavior with actual printing (preview)!
It is NOT possible to trigger the opening of a Google Sheets printing preview programamticaly!
The Javascript method you are using iframeElement.contentWindow.print() might trigger the printing of the whole content of a browser window (different from the Google Sheets printing dialog, also depends on the browser), but if you try to incorporate it into the client-side coe of an Apps Script project, you will most likely run into restrictions due to the scopes of modal diloags and usage of iframes.
While from your code it is hard to say either you implemented the funcitons in the correct files of the Apps Script project, keep in mind that to work with iframes you need to specify in function openUrl()
html.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);

Related

Why does Adobe Analytics call fail to fire even though DTM Switch shows the Satellite call?

I'm trying to attach a DTM Event Based Rule to a Social Share button from Add This, and it's not working.
I have other rules on the same page which are working fine, so I'm confident all the setup basics are correct.
In fact it almost works... In the log below... why does DTM Switch report event13 but then it doesn't show up in the Adobe Analytics Server Call?
Still not fully clear why it partially works (as opposed to not working at all), but the problem seems to be caused by attempting to bind Event Based Rules to elements that were injected into the DOM via Javascript (such as the AddThis API).
Solved by using a custom event handler to dispatch a Direct Call Rule:
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
onElementInserted("body", '.at-share-btn', function(element) {
$(element).one('click', function() {
var network = $($(this).find('title')[0]).text();
window.digitalData.event.socialNetwork = network;
_satellite.track('social-network');
return true;
});
});
});
</script>
where onElementInserted() is borrowed from jquery detecting div of certain class has been added to DOM
Is it an s.tl() beacon? Is event13 set in custom code? I'd doublecheck that s.linkTrackEvents is set to allow event13- see Omniture events is not firing/sending data via DTM when using s.tl tracking methods for more info on that.

NetSuite/Suitescript/Workflow: How do I open a URL from a field after clicking button?

I have a workflow that adds a button "Open Link" and a field on the record called "URL" that contains a hyperlink to an attachment in NetSuite. I want to add a workflow action script that opens this url in a different page. I have added the script and the workflow action to the workflow. My script:
function openURL() {
var url = nlapiGetFieldValue('custbody_url');
window.open(url);
}
I get this script error after clicking the button: "TypeError: Cannot find function open in object [object Object].
How can I change my script so it opens the URL in the field?
(This function works when I try it in the console)
Thanks!
Do you want it to work when the record is being viewed or edited? They have slightly different scripts. I'm going to assume you want the button to work when the record is being viewed, but I'll write it so it works even when the document is being edited as well.
The hard part about the way Netsuite has set it up is that it requires two scripts, a user event script, and a client script. The way #michoel suggests may work too... I've never inserted the script by text before personally though.
I'll try that sometime today perhaps.
Here's a user event you could use (haven't tested it myself though, so you should run it through a test before deploying it to everyone).
function userEvent_beforeLoad(type, form, request)
{
/*
Add the specified client script to the document that is being shown
It looks it up by id, so you'll want to make sure the id is correct
*/
form.setScript("customscript_my_client_script");
/*
Add a button to the page which calls the openURL() method from a client script
*/
form.addButton("custpage_open_url", "Open URL", "openURL()");
}
Use this as the Suitescript file for a User Event script. Set the Before Load function in the Script Page to userEvent_beforeLoad. Make sure to deploy it to the record you want it to run on.
Here's the client script to go with it.
function openURL()
{
/*
nlapiGetFieldValue() gets the url client side in a changeable field, which nlapiLookupField (which looks it up server side) can't do
if your url is hidden/unchanging or you only care about view mode, you can just get rid of the below and use nlapiLookupField() instead
*/
var url = nlapiGetFieldValue('custbody_url');
/*
nlapiGetFieldValue() doesn't work in view mode (it returns null), so we need to use nlapiLookupField() instead
if you only care about edit mode, you don't need to use nlapiLookupField so you can ignore this
*/
if(url == null)
{
var myType = nlapiGetRecordType();
var myId = nlapiGetRecordId();
url = nlapiLookupField(myType, myId,'custbody_url');
}
//opening up the url
window.open(url);
}
Add it as a Client Script, but don't make any deployments (the User Event Script will attach it to the form for you). Make sure this script has the id customscript_my_client_script (or whatever script id you used in the user event script in form.setScript()) or else this won't work.
Another thing to keep in mind is that each record can only have one script appended to it using form.setScript() (I think?) so you may want to title the user event script and client script something related to the form you are deploying it on. Using form.setScript is equivalent to setting the script value when you are in the Customize Form menu.
If you can get #michoel's answer working, that may end up being better because you're keeping the logic all in one script which (from my point of view) makes it easier to manage your Suitescripts.
The problem you are running into is that Workflow Action Scripts execute on the server side, so you are not able to perform client side actions like opening up a new tab. I would suggest using a User Event Script which can "inject" client code into the button onclick function.
function beforeLoad(type, form) {
var script = "window.open(nlapiGetFieldValue('custbody_url'))";
form.addButton('custpage_custom_button', 'Open URL', script);
}

Phonegap Build and WKWebView: What we have here is a failure to communicate

WKWebview and Phonegap Build: Is communication between index.js and WKWebView even possible?
I'm using Phonegap Build to generate my mobile device executables. I'm opening a webview and loading a page off our website. While using UIWebView I had no problem coding index.js on the mobile device to listen for a loadstop event and call executescript to execute javascript on the web page in the webview and return the results to index.js where I could do whatever I needed.
But UIWebView is dog-slow, so for iOS I've been trying to get WKWebView to work via the cordova-plugin-wkwebview-engine plug-in.
I can get the WKWebview to open my URL, and it is blazing fast compared to UIWebView, but after days of searching (every page containing 'WKWebView' and 'Phonegap' that Google knows of) and experimentation I have been unable to find any way to detect loadstop (or equivalent), nor have I found any way to execute a script in WKWebView from index.js.
I would probably be happy with ANY method to communicate between index.js and WKWebView. Is there a process similar to executescript after loadstop event, even if it is async? Is there some type of messaging capability?
I'd love to see some code examples for index.js.
I'm beginning to think that I'm going to have to break down and resort to learning native code in xcode to make this happen. I sure hope not because Phonegap Build has worked fine for me thus far.
Has anyone had any luck with this?
Here is the code that works under UIWebView. It works well enough under WKWebView to open the URL, but loadstop does not trigger and there is no execution of the script.
launchBrowserWindow: function (url) {
var ref;
try {
ref = window.open(url, '_self', 'location=no,toolbar=no');
} catch (e) {
console.log("McMApp catch window.open fail: " + url + " err: " + e.message);
}
try {
ref.addEventListener("loadstop", function () {
ref.executeScript(
{ code: 'window.location.search' },
function (value) {
var requestString = value[0];
console.log("McMApp loadstop request string: " + requestString);
});
});
} catch (e) {
console.log("McMApp FAIL ref.addeventlistener loadstop");
}
},
50 hard-boiled eggs to anyone that can help me get this working.
InAppBrowser is a fickle beast, so happy to help! For reference, I have an app now that uses InAppBrowser and WKWebView and both work using the following:
"LoadStop" not firing:
Self vs _blank:
I typically open the Browser via "_blank" instead of "self". Try that.
Newer versions of InAppBrowser should still be automatically aliased to 'window.open' but in the docs they mention this will go away soon. You can do that in the deviceready event like so:
window.open = cordova.InAppBrowser.open;
Or, and probably the safer option, just use "cordova.InAppBrowser.open".
Here's code I use. Try printing out or "alert"-ing the URLs that are coming through. They may not be what you expect, especially if there are multiple redirects.
var inAppBrowserRef = cordova.InAppBrowser.open("www.google.com", '_blank', 'location=no,toolbar=yes');
inAppBrowserRef.addEventListener('loadstop', function(event) {
console.log("loadstop: " + event.url);
alert("loadstop: " + event.url);
// run execute script code
}
});
Also, make sure any use of InAppBrowser is within/after the 'deviceready' event fires.
Execute Script Issue
I believe here the problem is that your code isn't firing. See here, wrap it into a function and call it immediately:
ref.executeScript(
{ code: 'var runCode = function() { window.location.search; } runCode();' },
function (value) {
var requestString = value[0];
console.log("McMApp loadstop request string: " + requestString);
});
I'm not totally sure, but according to MDN, shouldn't you be passing a parameter to the location search function too?
// Append "someData" as url parameter query
window.location.search = "someData";
Last, note that WKWebView does have lots of known issues currently. Always check first for known issues on GitHub or official Apache Cordova site, etc, because as you wrote, you can burn many hours getting nowhere. I'm currently using this fork of the WKWebView - this team is moving much faster than the "official" plugin fixing bugs so you might try that.

Is it possible to add buttons and control its event to toolbar of inappbrowser using javascript...?

I am developing a Hybrid App for iOS and Android using PhoneGap.Is it possible to add buttons and control its event to toolbar of inappbrowser using javascript.I know how to add it through ios native side but i cant use that process.I need to control the button event through a javascript method.
You have two options to do that.
The first option is, obviously, to patch the native plugin code, and that's it. Here you can find an example made for iOS, you will have to do the same to your Android Java code and for every other platform you want to support.
Another option is to hide the native toolbar and inject HTML and CSS to create a new one when the page is loaded.
Something like this:
// starting inappbrowser...
inAppWindow = window.open(URL_TO_LOAD, '_blank', 'location=no');
// Listen to the events, we need to know when the page is completely loaded
inAppWindow.addEventListener('loadstop', function () {
code = CustomHeader.html();
// Inject your JS code!
inAppWindow.executeScript({
code: code
}, function () {
console.log("injected (callback).");
});
// Inject CSS!
inAppWindow.insertCSS({
code: CustomHeader.css
}, function () {
console.log("CSS inserted!");
});
And you will have obviously to define the CustomHeader object, something like this:
var CustomHeader = {
css: '#customheader { your css here }',
html: function() {
var code = 'var div = document.createElement("div");\
div.id = "customheader";\
// Insert it just after the body tag
if (document.body.firstChild){ document.body.insertBefore(div, document.body.firstChild); } \
else { document.body.appendChild(div); }';
return code;
}
};
I had experience with this problem.
For my case, the second option was enough, not a critical task. Sometimes it takes a lot for the loadstop event to fire, and so you don't see the injected bar for >= 5 seconds.
And you have to pay attention even on the CSS of the loaded page, because obviously you can affect the original CSS, or the original CSS can affect the style of your toolbar.

Override web page's javascript function using firefox addon sdk

I'm trying to override a JS function named replaceMe in the web page from my add-on's content script, but I see that the original function implementation always gets executed.
Original HTML contains the following function definition:
function replaceMe()
{
alert('original');
}
I'm trying to override it my add-on like (main.js):
tabs.activeTab.attach({
contentScriptFile: self.data.url("replacerContent.js")
});
Here's what my replacerContent.js looks like:
this.replaceMe = function()
{
alert('overridden');
}
However, when I run my addon, I always see the text original being alerted, meaning the redefinition in replacerContent.js never took effect. Can you let me know why? replaceMe not being a privileged method, I should be allowed to override, eh?
This is because there is an intentional security between web content and content scripts. If you want to communicate between web content and you have control over the web page as well, you should use postMessage.
If you don't have control over the web page, there is a hacky workaround. In your content script you can access the window object of the page directly via the global variable unsafeWindow:
var aliased = unsafeWindow.somefunction;
unsafeWindow.somefunction = function(args) {
// do stuff
aliased(args);
}
There are two main caveats to this:
this is unsafe, so you should never trust data that comes from the page.
we have never considered the unsafeWindow hack and have plans to remove it and replace it with a safer api.
Rather than relying on unsafeWindow hack, consider using the DOM.
You can create a page script from a content script:
var script = 'rwt=function()();';
document.addEventListener('DOMContentLoaded', function() {
var scriptEl = document.createElement('script');
scriptEl.textContent = script;
document.head.appendChild(scriptEl);
});
The benefit of this approach is that you can use it in environments without unsafeWindow, e. g. chrome extensions.
You can then use postMessage or DOM events to communicate between the page script and the content script.

Resources