Open external anchor links from node-webkit - node.js

I'm making a game with Dart and I'm packaging it with node-webkit and node-webkit.dart (a Dart wrapper for node-webkit modules).
My goal is to have the node-webkit app game appear as a standalone native app. To achieve this I've stripped the navigation bar and some other things. All my assets are local, the game never has to connect to the internet.
I have a few anchor links within my HTML (leading to my site for example). When I click them currently my node-webkit window opens the link within itself. Besides this never being my plan, there's no way to return to the game since I took the navigation bar away.
So my question: Is it possible to make a handler that opens anchor links externally (in the user's browser of choice)? Bearing in mind that anchor links may be added dynamically.
I know about Shell.openExternal(url) but I can't think of a way to make every anchor link call it.
Thanks!

As it turns out, there's a node-webkit event to handle links but node-webkit.dart doesn't appear to support it.
To solve my issue I added an inline JS script to my main HTML file:
<script type="text/javascript">
try {
var gui = require('nw.gui');
var win = gui.Window.get();
win.on('new-win-policy', function (frame, url, policy) {
gui.Shell.openExternal(url);
policy.ignore();
});
} catch(e) { }
</script>
(The empty try/catch is there because an error is thrown when my game is run outside of the node environment).

Related

Trying to write to a json file using Node fs.writeFile

I hope I'm saying this correctly. What I'm trying to do is write to a json file using fs.writeFile.
I can get it to work using the command line but what I want to do is call a function maybe a button click to update the json file.
I figure I would need some type of call to the node server which is local port 8080. I was researching and seen somebody mention using .post but still can't wrap my head around how to write the logic.
$(".button").on("click", function(event) {
fs.writeFile("./updateme.json", "{test: 1}", function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
});
});
Using jQuery along with fs? Wow that could be great! Unfortunately that is not as simple as that!
Let me introduce you to server-side VS client-side JavaScript. Well actually there are a lot of resources on the net about that - just google it, or check the answers to this other StackOverflow question. Basically JavaScript can run either on a browser (Chrome, Mozilla...) or as a program (usually a server written in NodeJS), and while the language is (almost) the same, both platforms don't have the same features.
The script that you're showing should run in a browser, because it's using jQuery and interacting with buttons and stuff (aka the DOM). Can you imagine what a mess it would be if that script could interact with the file system? Any page you'll visit will be able to crawl around in your holiday pictures and other personal stuff you keep on your computer. Bad idea! That is why some libraries like fs are not available in the browser.
Similarly, some libraries like jQuery are not available (or simply useless) in the server, because there is no HTML and user interaction, only headless programs running.
So, what can I do to write a JSON file after a user clicks on a button?
You can set up:
A NodeJS server that will write a JSON file
Make jQuery call this server with the data to be written after the user clicks on a button
If you want further guidelines on this, tell me in the comments! I'll be ready to edit my question so as to include instructions on setting up such an environment.

nwjs reactjs, confused about my context. Document is undefined

In my nwjs application i am using React to build my UI. Currently, React is being loaded via a <script> tag in the main file, index.html. index.html has another <script> tag which loads main.js containing code which defines and renders my React components as well as requiring (require()) a few Node modules such as "fs" and "McFly".
This all seems to be working, however when i try using another node module (react-inlinesvg) i get an error, "document is undefined".
Having looked online for help, i have come to the conclusion that React now believes that it is being run on the server? Which is odd, as before i started using the react-inlinesvg module it was happily rendering components using React.render (clientside rendering).
If you need any more context or information then please ask.
It could be that you are rendering on the server side, or also that you are rendering both sides. In the second case you could simple nest the line that is causing you error with:
if (process.env.BROWSER) {
the line causing the error
}
If the error disappears, it means that you are on the server side also!
I hope this helps...
Basically if you code is universal (or isomorphic, if you want...) with this check you can execute the code only on client side, you want to do this to use a particular style-sheet for example:
if (process.env.BROWSER) {
require("../style/main.scss");
}
Naturally if you want to do stuff server-side you can check
if (!process.env.BROWSER) {
}
if any one face this he can solve it in 2 ways:
Solution 1: if you are using nw.js 15 or above try to enable mix context mode:
in your package.json add this flag:
"chromium-args": "--mixed-context"
Solution 2: expose document to the global object using this hack:
global.document = window.document;

Handling WinJS app upon relaunch

When back home is pressed app exists but it is not terminated yet.
When user press primary or secondary tile app is relauched.
Default way is to let application navigate to the last visited page in the navigation history.
I don't know if there is a bug but this way doesn't work as expected because any code inside page ready function executes but it doesn't count later when page is rendered. Static binding works but not dynamic.
I need to know what is the proper way of handling relaunch in an app that uses default navigation template?
What to do if I want clean start, destroy everything and than navigate to home?
How to overcome problem with framework not taking into consideration code inside page ready function?
Upon app initialization you should check for the ApplicationExecutionState, and do whatever you want in either case.
Thanks for your answer but it is quite clear from the start how to obtain ApplicationExecutionState.
Actually what I need was to execute all bindings and other post processing after DOM has been loaded in a promise timeout.
if (app.sessionState.previousExecutionState === 1) {
WinJS.Promise.timeout().then(function () {
performeAfterProcessing();
});
}
else {
performeAfterProcessing();
}
So if everyone encounters some strange behavior after application has been relaunched try to execute your code using promise timeout.

Drag 'n' Drop files to a Chrome Package App?

Has anyone successfully implemented drag and drop with files from desktop to the app?
I've tried just putting this drag 'n' drop example into the index file but I just get this error:
Can't open same-window link to "file:///C:/Users....whatever"; try target="_blank".
Please share your stories, what you've tried and if you have succeed :)
Some resources to help you:
New Chrome Packaged Apps codelab that we've been working on covers drag-and-drop in both AngularJS and pure JavaScript.
AngularJS drag-and-drop: https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/angularjs/2_drop_files
JavaScript drag-and-drop: https://github.com/GoogleChrome/chrome-app-codelab/tree/master/lab5_data/javascript/2_drop_files
There's an early version of docs too for AngularJS drag-and-drop for Chrome at developer.chrome.com/trunk/apps/app_codelab5_data.html#handle_drag_and_dropped_files_and_urls
We're working on the docs to cover both samples though.
I have done this a while ago and it worked.
The problem you've got is that you are creating a file url, then trying to navigate to the url. The navigation is failing, not the read. It's failing due to CSP, and you probably won't be able to override that with a different CSP due to security restrictions we've placed on allowable CSPs.
But, you should be able to just read the file and use the content. You need to change that sample code to use ReadAsText or ReadAsArrayBuffer instead of readAsDataURL. Look here for more details.
Please let us know how you get on!
Just listening for drop won't work. You will have to prevent the default functionality of dragover.
document.body.addEventListener('dragover', function(e) {
e.preventDefault();
}
document.body.addEventListener('drop', function(e) {
alert('it works!')
}

Is there a way to refresh your phonegap application - eg, build the page and start running the scripts from the beginning?

Is there any way to do this?
E.g., if a user starts the app with no internet connection, no remote scripts can be loaded, and the application basically can't run and I display a "No internet" page. But if the user gets internet later and the application is still running, is there any way to just "restart" ?
how about -
document.location = "index.html"
PhoneGap applications are just like an embedded website - you should be able to go to any hyperlink you wish (mind the whitelists).
Of course, if you also want to detect when it's again online, you should use the PhoneGap Network API to bind to those online/offline events.
In general thought, have you ever thought of using the HTML5 manifest functionality to actually let your local PhoneGap app cache those remote scripts? That way your app could still run, even when offline (except if it needs remote data to "do your thing")...
Hope this helps!
Try this
navigator.app.loadUrl("file:///android_asset/www/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
Accepted solution works, but might fail if you have an SPA with html5 url routing.
Here's a safest solution:
// keep startup url (in case your app is an SPA with html5 url routing)
var initialHref = window.location.href;
function restartApplication() {
// Show splash screen (useful if your app takes time to load)
navigator.splashscreen.show();
// Reload original app url (ie your index.html file)
window.location = initialHref;
}

Resources