How do you use getHtmlPrintDocumentSourceAsync to print in HTML/JavaScript Windows Store apps? - windows-runtime

I am very simply trying to print some content in a Windows 10 app (Universal) using HTML and JavaScript/WinJS.
ALL of the documentation says that there is a function on MSApp called getHtmlPrintDocumentSource.
I do not have this, nor can I seem to find any relevant source to see if it may have been moved. I instead have getHtmlPrintDocumentSourceAsync. This seems to be a replacement for the former, but I cannot get it to work and there is zero documentation on it as far as I can tell.
When I run the below code (which is based on the documentation but updated to be async):
function onPrintTaskRequested(printEvent) {
var printTask = printEvent.request.createPrintTask("Print Sample", function (args) {
MSApp.getHtmlPrintDocumentSourceAsync(document)
.then(function(result) {
args.setSource(result);
});
printTask.oncompleted = onPrintTaskCompleted;
});
}
result is populated with some of the print settings as I would expect, but the content property is set to 0, which I am guessing is the problem. I can't really be sure as there is no documentation for this function. I can't even run any of the dozens of pieces of example code in the documentation using `getHtmlPrintDocumentSource' because it seemingly doesn't exist anymore.
In addition to just sending document to the Async method, I have tried a couple of different variations of creating document fragments. Same results.
Probably not terribly helpful, but the message in the Windows Print Dialog that opens when executing the above code is: "Nothing was sent to print. Open a document and print again."
Any ideas?

getHtmlPrintDocumentSource is a synchronous deprecated API in Windows 10 apps. We'll work on some of the docs left behind for Windows 8 and 8.1 to clarify that.
Check out https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/Printing/js for an example of how to use getHtmlPrintDocumentSourceAsync in JavaScript.
Here is the code:
// Needs to be invoked before calling the print API
function registerForPrintContract() {
var printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
printManager.onprinttaskrequested = onPrintTaskRequested;
console.log("Print Contract registered. Use the Print button to print.", "sample", "status");
}
// Variable to hold the document source to print
var gHtmlPrintDocumentSource = null;
// Print event handler for printing via the PrintManager API.
function onPrintTaskRequested(printEvent) {
var printTask = printEvent.request.createPrintTask("Print Sample", function (args) {
args.setSource(gHtmlPrintDocumentSource);
// Register the handler for print task completion event
printTask.oncompleted = onPrintTaskCompleted;
});
}
// Print Task event handler is invoked when the print job is completed.
function onPrintTaskCompleted(printTaskCompletionEvent) {
// Notify the user about the failure
if (printTaskCompletionEvent.completion === Windows.Graphics.Printing.PrintTaskCompletion.failed) {
console.log("Failed to print.", "sample", "error");
}
}
// Executed just before printing.
var beforePrint = function () {
// Replace with code to be executed just before printing the current document:
};
// Executed immediately after printing.
var afterPrint = function () {
// Replace with code to be executed immediately after printing the current document:
};
function printButtonHandler() {
// Optionally, functions to be executed immediately before and after printing can be configured as following:
window.document.body.onbeforeprint = beforePrint;
window.document.body.onafterprint = afterPrint;
// Get document source to print
MSApp.getHtmlPrintDocumentSourceAsync(document).then(function (htmlPrintDocumentSource) {
gHtmlPrintDocumentSource = htmlPrintDocumentSource;
// If the print contract is registered, the print experience is invoked.
Windows.Graphics.Printing.PrintManager.showPrintUIAsync();
});
}

Related

Facing Issue on Getting Current Tabs and Selected Tab URL on Chrome API

I am trying to get the URL of all opened Tabs and Selected Tab using thiese two snippet
// For Getting URL of All Opened Tabs
chrome.tabs.getCurrent(function(tabs) {
for (var i = 0; i < tabs.length; i++) {
console.log(tab.url);
}
});
// For Getting URL of Selected Tab
chrome.tabs.getSelected(function(tab) {
console.log(tab.url);
});
but neither of them working. For getting All Tabs I am getting this error:
Error in response to tabs.getCurrent: TypeError: Cannot read property 'length' of undefined
and for getting the selected Tab
undefined
can you please let me know why this is happening and how can I fix it?
chrome.tabs.getSelected has been deprecated. so we should use tabs.query({active: true}... instead.
chrome.tabs.getCurrent passes a single tab to the callback function. It doesn't "Getting URL of All Opened Tabs", it:
Gets the tab that this script call is being made from. May be undefined if called from a non-tab context (for example: a background page or popup view).
So:
// Write the URL of the current tab to the console
chrome.tabs.getCurrent(tab => console.log(tab.url));
This requires the "activeTab" or "tabs" permission in the manifest. If there is an error it won't throw an exception, instead it will populate chrome.runtime.lastError.
I find it easier to deal with all the callbacks using an asynchronous or promise wrapper library like chrome-extension-async. This let's us use async/await syntax and a regular try-catch:
try {
const currentTab = await chrome.tabs.getCurrent();
console.log(currentTab.url);
}
catch(err) {
// Handle errors
}
In your popup.html you can't access chrome.tabs.getCurrent - you have to use chrome.tabs.query instead:
async function writeAllTabUrlToConsole() {
try {
// Get all the tabs
const tabs = await chrome.tabs.query({});
// Write all their URLs to the popup's console
for(let t of tabs)
console.log(t.url, t.active);
}
catch(err) {
// Handle errors
}
}

Change html page with jqm (1.4.0), passing parameter

I am building several apps and want to be able to reuse som code as separate HTML pages by passing parameters to them.
I would really like to pass parameters via ajax with one of these:
Alt1
$.mobile.pageContainer.pagecontainer("change", "../Photo/Photo.html", { reload: true, parameter: "dummyParameter"});
$.mobile.changePage("../Photo/Photo.html", { reloadPage: true, parameter: "dummyParameter"});
Problem is that the page wont reload.
If I use the below link the page is loaded/reloaded, but I cant seem to find the passed parameter.
Alt2
Or through a basic link
(I would prefeer to not generate the url in javascript as in alt2 but if what it takes...)
I use this code to try to retreive the parameters:
$(document).on("pagebeforechange", function (e, data) {
if (data.toPage[0].id == "Photo") {
//var parameters = $(this).data("url").split("?")[1];
//var parameter = parameters.replace("paremeter=", "");
var stuff = data.options.stuff;
//showStuff("#p2", stuff);
}
});
While I'm at it, if someone uses type script. Visual studio complains about that this call signature isnt correct:
$(document).on("pagebeforechange", function (e, data)
Expects one argument, the event, not the data. The plugin generates correct javascript but the IDE complains.
Thanks!

Chromecast Launch, what's with the DIAL parameters? Aren't I runing MY application, not some registered standard?

The following code displays a proper list of available chromecast devices on my network. But when I click on the links, the application never launches. There are a couple of things that I'm quite confused about that may or may not be related to this question:
If I'm making my own custom application, what's with the DIAL parameters and why do I have to pass them? I don't want to write an app for the DIAL standard... this is MY app.
Again related to the DIAL parameters, if I search for devices with any other query other than "YouTube" (a DIAL parameter), the list always comes up blank. I suppose I shouldn't care, as long as the device is listed... but again... the app won't launch.
It should be noted that my sender app is a chrome webpage.
I'm a bit confused as to where my "appid" goes int he launch parameters,'
<html data-cast-api-enabled="true">
<body>
hi!<BR/>
<script>
var cast_api, cv_activity;
if (window.cast && window.cast.isAvailable) {
// Cast is known to be available
initializeApi();
} else {
// Wait for API to post a message to us
window.addEventListener("message", function(event) {
if (event.source == window && event.data &&
event.data.source == "CastApi" &&
event.data.event == "Hello")
{
//document.write("Initialize via message.<br/>");
initializeApi();
//document.write("Api initialized via message.");
};
});
};
initializeApi = function() {
cast_api = new cast.Api();
cast_api.addReceiverListener("YouTube", onReceiverList);
};
var g_list;
onReceiverList = function(list) {
g_list = list;
// If the list is non-empty, show a widget with
// the friendly names of receivers.
// When a receiver is picked, invoke doLaunch with the receiver.
document.write("Receivers: "+list.length+"<br/>");
var t;
for(t=0;t<list.length;t++)
document.write('found:'+list[t].name+' ' +list[t].id+'<br/>');
};
onLaunch = function(activity) {
if (activity.status == "running") {
cv_activity = activity;
// update UI to reflect that the receiver has received the
// launch command and should start video playback.
} else if (activity.status == "error") {
cv_activity = null;
}
};
function launchy(idx)
{
doLaunch(g_list[idx]);
}
doLaunch = function(receiver) {
var request = new window.cast.LaunchRequest(">>>>>what REALLY goes here?<<<<<<< ", receiver);
request.parameters = "v=abcdefg";
request.description = new window.cast.LaunchDescription();
request.description.text = "My Cat Video";
request.description.url = "http://my.website.get.your.own/chomecast/test.php";
cast_api.launch(request, onLaunch);
};
stopPlayback = function() {
if (cv_activity) {
cast_api.stopActivity(cv_activity.activityId);
}
};
</script>
</body>
</html>
The part marked "what really goes here?" is the part that I THINK is wrong... I couldn't be completely wrong. My device is white listed, I have an appid (which I thought might go in that slot)... The documentation merely says ActivityType DIAL Parmeters are valid, mandatory.
The first argument to the LaunchRequest is your App ID, the one that you have received in an email as part of whitelisting process. Also, the "YouTube" in the initialize method should also be replaced with the same App ID.
I strongly suggest you look at the sample that is on GitHub for chrome sender to see how you can send a request to load a media on a cast device.

How do you detect that a script was loaded *and* executed in a chrome extension?

I've been tracking down a bug for days... then I realized the bug was me. :/
I had been using webRequest.onComplete, filtered for scripts. My error was that I made the incorrect association between the scripts being loaded and being executed. The get loaded in a different order than they get executed, and thus the timing of the events is not in the order I need them in. I need to inject between certain scripts so I need an event right after a file has been executed and before the next one.
The only solution I can think of at the moment is to alter the JS being loaded before it gets executed. But it makes my stomach turn. And the bfcache would wreak even more havoc, so not a great solution either.
I would use the HTML5 spec's afterscriptexecute, but that is not implemented in Chrome. Is there another API, perhaps an extension API that I can use?
Note: This method no longer works as of Chrome 36. There are no direct alternatives.
Note: The answer below only applies to external scripts, i.e. those loaded with <script src>.
In Chrome (and Safari), the "beforeload" event is triggered right before a resource is loaded. This event allows one to block the resource, so that the script is never fetched. In this event, you can determine whether the loaded resource is a script, and check whether you want to perform some action
This event can be used to emulate beforescriptexecute / afterscriptexecute:
document.addEventListener('beforeload', function(event) {
var target = event.target;
if (target.nodeName.toUpperCase() !== 'SCRIPT') return;
var dispatchEvent = function(name, bubbles, cancelable) {
var evt = new CustomEvent(name, {
bubbles: bubbles,
cancelable: cancelable
});
target.dispatchEvent(evt);
if (evt.defaultPrevented) {
event.preventDefault();
}
};
var onload = function() {
cleanup();
dispatchEvent('afterscriptexecute', true, false);
};
var cleanup = function() {
target.removeEventListener('load', onload, true);
target.removeEventListener('error', cleanup, true);
}
target.addEventListener('error', cleanup, true);
target.addEventListener('load', onload, true);
dispatchEvent('beforescriptexecute', true, true);
}, true);
The dispatch times are not 100% identical to the original ones, but it is sufficient for most cases. This is the time line for the (non-emulated) events:
beforeload Before the network request is started
beforescriptexecute Before a script executes
afterscriptexecute After a script executes
onload After the script has executed
Here's an easy way to see that the events are working as expected:
window.addEventListener('afterscriptexecute', function() {
alert(window.x);
});
document.head.appendChild(document.createElement('script')).src = 'data:,x=1';
document.head.appendChild(document.createElement('script')).src = 'data:,x=2';
The demo can be seen live at http://jsfiddle.net/sDaZt/
I'm not familiar with Chrome Extensions (only browser javascript), but I think that you will unfortunately have to edit your loaded JS so that is calls a function of your choice when it is executed, if you want to do this nicely. This it what Google does for asynchronously loading its Maps Javascript file:
function loadScript() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?sensor=false&callback=executed";
document.body.appendChild(script);
}
function executed() {
/* Google maps has finished loading, do awesome things ! */
}
If you really don't want to edit your loaded JS files, you could have a setInterval (or a recursive function with setTimeout) checking regularly if some functions or variables are initialized.
Have you tried script loading using Modernizr.js?
I had a similar issue, where the timing of script loading was causing conflict. I used Modernizr.js, which includes the library yepnope.js by default. Below is an example of some scripts I loaded conditionally. You can include a test clause, or simply load them in the order you prefer, with the guarantee that they will load and execute in the order you wish due to the callback.
Here is an example with a conditional clause:
Modernizr.load({
test: false, //Or whatever else you'd like. Can be conditional, or not so conditional
yep: {
'script1': 'MyJavascriptLibrary1.js'
},
nope: {
'script2': 'MyJavascriptLibrary2.js',
'script3': 'MyJavascriptLibrary3.js'
},
callback: {
'script1': function (url, result, key) {
console.log('MyJavascriptLibrary1.js loaded'); //will not load in this example
},
'script2': function (url, result, key) {
console.log('MyJavascriptLibrary2.js loaded first');
},
'script3': function (url, result, key) {
console.log('MyJavascriptLibrary3.js loaded second');
}
}
});
If triggering false, MyJavascriptLibrary2.js and MyJavascriptLibrary3.js will load in the appropriate order, no matter what elements influence how they would behave normally (file size, connection speed, etc.). In these callbacks, you may fire additional javascript as well, in the order you wish to do so. Example:
'script2': function (url, result, key) {
alert('anything in here will fire before MyJavascriptLibrary3.js executes');
},
Note this can be done without Modernizr.load({...
but using simply yepnope({...
For more documentation, check out the yepnope.js API

HTML5/websockets/javascript based real-time logfile viewer?

Im looking for the equivalent of "tail -f" that runs in a browser using html5 or javascript.
A solution would need a client side code written in HTML5/websockets/javascript and a back-end server side application. Im looking for one in c# but i'm willing to rewrite it from php or python.
This is the only thing that i've seen that comes close is
http://commavee.com/2007/04/13/ajax-logfile-tailer-viewer/
However, modern browsers have WebSockets which makes the problem much simpler.
http://www.websocket.org/echo.html
Ideally, I would like to have some of the capabilities of BareTail
http://www.baremetalsoft.com/baretail/
Such as Color Coding of lines, sorting and multi-file tabbing.
I have located a similar posting where someone is looking for windows based log file programs
https://stackoverflow.com/questions/113121/best-tail-log-file-visualization-freeware-tool
Anyone have any suggestions?
It is not exactly like tail but the live logs feature of https://log4sure.com does allow you to monitor your client side logs realtime. You would have to setup and do the logs appropriately as you would do for tailing, but you can see all the logs with extra information about your client, example browser, os, country etc. You can also create your own custom logs to log stuff. Checkout the demo on the site to get a better idea.
The setup code is really easy, and the best part is, its free.
// set up
var _logServer;
(function() {
var ls = document.createElement('script');
ls.type = 'text/javascript';
ls.async = true;
ls.src = 'https://log4sure.com/ScriptsExt/log4sure-0.1.min.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ls, s);
ls.onload = function() {
// use your token here.
_logServer = new LogServer("use-your-token-here");
};
})();
// example for logging text
_logServer.logText("your log message goes here.")
// example for logging error
divide = function(numerator, divisor) {
try {
if (parseFloat(value) && parseFloat(divisor)) {
throw new TypeError("Invalid input", "myfile.js", 12, {
value: value,
divisor: divisor
});
} else {
if (divisor == 0) {
throw new RangeError("Divide by 0", "myfile.js", 15, {
value: value,
divisor: divisor
});
}
}
} catch (e) {
_logServer.logError(e.name, e.message, e.stack);
}
}
// another use of logError in window.onerror
// must be careful with window.onerror as you might be overwriting some one else's window.onerror functionality
// also someone else can overwrite window.onerror.
window.onerror = function(msg, url, line, column, err) {
// may want to check if url belongs to your javascript file
var data = {
url: url,
line: line,
column: column,
}
_logServer.logError(err.name, err.message, err.stack, data);
};
//example for custom logs
var foo = "some variable value";
var bar = "another variable value";
var flag = "false";
var temp = "yet another variable value";
_logServer.log(foo, bar, flag, temp);
While I wish it had better JSON object prettification for live tailing and historical logs, the following JS client works and supports your server-side requirement also:
https://github.com/logentries/le_js/wiki/API
<html lang="en">
<head>
<title>Your page</title>
<script src="/js/le.min.js"></script>
<script>
// Set up le.js
LE.init('YOUR-LOG-TOKEN');
</script>
</head>
.....
<script>
// log something
LE.log("Hello, logger!");
</script>
Personally to get the above code to work however, I've had to add the following line of code just above LE.init('YOUR-LOG-TOKEN'):
window.LEENDPOINT = 'js.logentries.com/v1'
.. Alternatively, Loggly may be a fit as well: https://www.loggly.com/docs/javascript/