The javascript isomorphic application with IMA.js - javascript

I tried creating my first javascript isomorphic application with IMA.js framework (https://github.com/seznam/IMA.js-skeleton
). At first glance I have a few questions:
Calling "gulp.dev" opens new Chrome window.
a) Why Chrome? Can I change it? What if I use Firefox? What if I don't have Chrome at all?
b) Why can't I close the window?
There's recommendation for using IMAError. Why is that?
Why do I have to forward $Utils to props? What is it's function?
How exactly communicates Controller with View?

I will try answer your questions:
IMA.js has unit tests that are launched on file saved. For running IMA.js and your tests is used Karma. Karma need some launcher.
a) Chrome is used as a default launcher for Karma. In karma.conf it is possible to change one loader to another one (Firefox, Opera, ...)
b) You need this browser window for tests. When PhantomJS 2.0 launcher will be released, it will be the default launcher. After this change it will run in background.
IMAError is inherited from native error. But it gives you the option to add other parameters into error data - for example: status code, url etc. It solves some issues with stack, too.
$Utils is the set of utilities, helpers or tools for React components. It allows you to pass whatever you want into the component. For example: Router for link generation, Dictionary for translations, EventBus for firing events to controller etc. $Utils are automatically available in this.utils property inside every component that have $Utils property set.
Controller is setting React state of view. (See https://medium.com/react-tutorials/react-state-14a6d4f736f5) From View to Controller communication you could use EventBus or whatever you want (Dispatcher).

Related

How to know if service worker was updated in gatsby-plugin-offline

I've installed gatsby-plugin-offline, It works fine, but I want to listen for sw update event so I can notify user that new version of app is available.
Prior to this I used offline-plugin Which I speculate is behinde gatsby's plugin? They have doc explaining how to achieve what I want here: https://github.com/NekR/offline-plugin/blob/master/docs/updates.md but I can't figure out how to get these events via gatsby, any suggestions guys?
Currently gatsby-plugin-offline is a wrapper around sw-precache, and doesn't provide any direct hooks into much beyond the caching settings shown in the config options. It looks like there are a few ways around this via sw-precache, so it might be worth working on a PR or feature request over on the gatsby issues page.
I was looking for exactly the same answer.
There is an event you can hook into called "onServiceWorkerUpdateFound".
Just create (if you don't have already) a gatsby-browser.js file and do something like this.
gatsby-browser.js
exports.onServiceWorkerUpdateFound = () => {
// do something
};
I created a <div> that shows a "new version available" message with an onClick event that reloads the page (this then will activate the new service worker).
More Information: Gatsby Browser APIs

Parent view not setting global variable on <webview> in Electron after updating

I am trying to require a module in a guest page (angular controller).
When the application used an older version of node (0.30.5) it worked perfectly well. However i've had to upgrade electron to the latest version (0.37.6), and ive updated all uses of ipc in the electron application, so that it's now ipcMain and ipcRenderer.
Previously the angular controller managed to require the module using:
var ipc = window['require']('ipc');
So i thought that changing it to:
var ipcRenderer = window['require']('electron').ipcRenderer;
However that does not work and it states that window.require is not a function. I've tried multiple times to get it to work with other methods, however nothing works so far.
The problem is that require is undefined, however require is set in the html file that contains the <webview>, so it should be defined.
The <webview> goes to a URL which returns a <div> that uses angular.
The angular controller that is used in that <div> is no longer working, as the module I need is the first thing to be set in the file, and it is undefined
EDIT:
I can now see that the property that I set in the html is visible in the application debugger, however it does not appear in the webview debugger.
So I can only assume the parent view does not pass on the value to the <webview>. So if anyone knows why it doesn't pass on the value or what I need to do to set it, I would appreciate any information.
So as of the current version of Electron (0.37.6) the way to set a global variable is to specify a preload script on the preload attribute on the <webview> tag. For example in the preload script:
window['ipcRenderer'] = require('electron').ipcRenderer;
This will allow the guest page that the <webview> is displaying, to use the ipcRenderer. It seems like the previous method i was using, which was setting the global variable in the parent view HTML, does not work anymore
It's a quite old way to require electron modules. Here's the new one:
var ipcRenderer = require('electron').ipcRenderer;

Firefox extension: Access to main document from sidebar

I'm brand new to writing Firefox extensions and I'm trying to create a sidebar which searches for certain elements in the main document and shows info about them in the sidebar. I followed the instructions here to create the sidebar with no problems.
Problem I'm having now is accessing the main window or document in my sidebar.js file.
The docs here say to use
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
But that gives me this error:
TypeError: window.QueryInterface is not a function
I'm getting the warning:
The Components object is deprecated. It will soon be removed.
Which makes me think even if the code above worked for me it's not the best method.
The error messages indicate that your code is running in an unprivileged javascript context. .QueryInterface() is XPCOM code, i.e. accessing internal browser components which is only available to privileged code.
It is generally not advisable to for "leaf content" (windows/sidebars spawned by addons) to have direct control. Instead your addon main code should coordinate the individual views. Your sidebar should be dumb, just pass messages to addon code and the addon then modifies the content of the tab.
Due e10s various parts of the browser may end up running in separate processes in the future and will not have direct access to each other.
If you're not developing with the addon-sdk - which is designed with message-passing as its primary way of gluing components together - you will have to use the message manager to wire your addon, sidebar and content scripts together.
Use tabs.create() | MDN as in:
browser.tabs.create({url:"https://www.google.com"});
I also used that documentation and I also got that error. The documentation is too old.
browser.tabs.create({url:"https://www.google.com"})
will work fine

Angular routing without changing location

Chrome Packaged Apps have a rather strict Content Security Policy. One result of this is that manipulating the location (like clicking on a link) results in:
'Can't open same-window link to "chrome-extension://lkjasdfjklbdskjasdfjkhfdshjksad/derp.html"; try target="_blank". '
Target _blank will open the link in chrome which is not what I want. Can AngularJS' routing work in such a locked-down environment?
They docs give an example of an Angular app, but conspicuously does not use routing.
Update
Here is the link that, when clicked, gives the error: <a class='walrus-link' ng-href='paystubs/{{walrus.id}}'>Walrus {{id}}!</a>
Instead of using an href, try using ng-click and call a method to your controller the relocates to the appropriate page using $location. See the documentation on the AngularJS site. The following quote from the doc gives an indication that the $location service might be appropriate for you:
When should I use $location? Any time your application needs to react
to a change in the current URL or if you want to change the current
URL in the browser.
Your code might look something like this:
<a class='walrus-link' ng-click='getPaystub(walrus.id)'>Walrus {{id}}!</a>
and in your parent controller, you'll need a scope method called 'getPaystub' with a line similar to:
$scope.getPaystub = function(selectedWalrusId) {
$location.path('paystubs/'+$scope.walrus.id);
}
This way angular keeps control and won't cause a page refresh. This hopefully keeps you within the bounds of the CSP. Unfortunately I cannot test this in a packaged app, but I've used the exact same convention in a web app and it works just dandy.
routing works for me in my chrome app when not using $routeProvider's html5 mode (which is disabled by default), you just have to use a hash in the url.
so my links look like this:
About
$routeProvider configuration is as follows:
$routeProvider.when('/about', {templateUrl:'about.html'})

UIWebView Javascript Window to Window Communication

I'm working on an iOS app in which I'm trying to use UIWebView to display a variety of websites. Recently I finished logic to inject Javascript into the UIWebView to catch instances of window.open, window.close, and window.opener.focus. In short, to do so, I inject JS that overrides the aforementioned JS functions, which includes creating an iframe with a specific scheme that I can catch in the app's webView:shouldStartLoadWithRequest:navigationType method. This is all working OK for now, including window.open creating a new UIWebView rather than loading in the same window.
Now though, the issue has come up where there's no feasible solution for JS communication between windows. If the child window tries to call to window.opener or window.parent, it's always returning a null value, and thus, it can't communicate back to the original web view.
In an effort to see what iOS browsers are able to effectively perform window-to-window communication, I found that of the 9 browsers I have on my iPhone, only Safari was able to effectively perform this communication successfully. This leads me to believe that there's something with UIWebView that prevents full JS window-to-window communication from being possible.
Has anyone had any success with getting UIWebView to fully integrate with all JS logic, namely window-to-window communication? Or have proof that JS window-to-window communication isn't possible? Any direction or advice is appreciated. Thanks!
Found possible solution.
Add JavaScriptCore.framework to Linked Frameworks and in your webViewDidFinishLoad:
JSContext *parentCtx = [self.parentWebView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
JSContext *childCtx = [self.childWebView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
childCtx[#"window"][#"opener"] = parentCtx[#"window"];
Now when you call window.opener.test() from childWebView, it will fire test function in parentWebView!
I'm not sure about private API.
Works on iOS 7 only
Swift version
import JavaScriptCore
let jsContextA = webA.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext")
let jsContextB = webB.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext")
//Original objc code : jsContextB[#"window"][#"opener"] = jsContextA[#"window"];
jsContextB!.setObject("opener", forKeyedSubscript: "window")
jsContextB!.setObject(jsContextA!.objectForKeyedSubscript("window"), forKeyedSubscript: "opener")

Categories

Resources