How to use x3dom with polymer? - polymer

I have a polymer site where I'd like to use the x3dom library to view an external x3d file, and simply be able to rotate the loaded 3D scene 360 degrees.
Has anyone successfully used x3dom with polymer? I don't see any reason why this wouldn't work. Please assume I have all the polymer stuff correct (which I have) and have loaded the prerequisite x3dom.js script and x3dom.css in the head of the page too. This is just a stripped down code snippet to show key bits:
<x3d width='350px' height='400px'>
<scene>
<inline nameSpaceName="myNS" mapDEFToID="true" url="{{_x3dPath}}"></inline>
</scene>
</x3d>
<script>
Polymer({
properties: {
_x3dPath: {type: String},
},
ready: function() {
this._x3dPath = "/someDynamicPath/threeDfile.x3d";
}
});
</script>
Any suggestions?

You need to create a custom element that serves as a wrapper for the 3rd party library. (e.g x3dom-wrapper.html ).
Inside that file, you must add the script reference to x3dom .js
<script type="text/javascript" src='../bower_components/x3dom/x3dom.js'></script>
Then, you need to import the wrapper custom element like any other polymer component. That way you ensure the x3dom dependency will be available when you need it.
Edit:
Wrapping the library is still a good practice but not the cause of your problem. I did a quick test and found that you must call x3dom.reload() on your "ready" polymer event handler. That way x3dom system reloads properly

Related

Modernizer is not defined

I have included this code in my script. Can someone tell me step by step how to install Modernizer in a page, in English layman point of view?
if(Modernizer.geolocation){
alert("geolocation is supported");
}
"Modernizr is not defined" happens when you try to reference it somewhere in a code but have not included it previously.
You may have your
if(Modernizer.geolocation)
call before Modernizr is included, or you have not included it at all. There is also a case when Modernizr is included but within asynchronous script (in that case, there might be something like <script src="modernizr.js" async></script>).
How to include Modernizr - the easiest way?
First choose your detects - a set of features your custom built version of Modernizr will test:
https://modernizr.com/download
Than save it as modernizer.js somewhere in your source tree, for example 'js/modernizr.rs'. Include it in a script tag before first Modernizr call. Like:
<script src="js/modernizr.rs"></script>
<script>
if(Modernizer.geolocation){
alert("geolocation is supported");
}
</script>

How to structure a Polymer SPA?

I'm new to Polymer 1.0.
I get the whole "everything is an element" philosophy but, to what extent?
How to structure all theses elements together?
TL;DR: Is there an equivalent to the main() function with Polymer and WebComponents in general ? If so , where should it be and what should it do ?
I usually look at examples, demos and projects to see how it should work, but because Polymer is so new (especially v1.0), I have a hard time finding non-trivial examples.
Long version
I get how to use Polymer to create elements.
But I'm hitting a roadbloack when I want to interface them. What structure shoud I use to make components talk between them.
Coming from an Angular background I have a relatively precise view of what should go where.
For example: the data is contained within scopes which are accessible from controllers, directives and html elements and you can use services to pull data from different part of the app.
In Polymer I don't get where are the boundaries of the data.
Not in the component itself but outside of it, where it lives and if another component can access it.
A simple drawing could help me a lot. There is no such thing explained in the polymer docs, probably because it's broader than Polymer.
To give you insights on my problem this is what I came across:
I set up a SPA based on Polymer Starter Kit
I wanted to wire it to firebase with the firebase-element
I created my own element which itself use <firebase-auth>:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/firebase-element/firebase-auth.html">
<dom-module id="my-login">
<template>
<firebase-auth id="firebaseLogin"
user="{{user}}"
location="https://my-project.firebaseio.com"
provider="facebook"
on-error="_errorHandler"
on-login="_loginHandler"></firebase-auth>
<button on-tap="login">Login with facebook</button>
<button on-tap="logout">Logout</button>
</template>
</dom-module>
<script>
Polymer({
is: 'my-login',
properties: {
successRedirect: String
},
_errorHandler: function(e){
console.log(e.detail);
},
_loginHandler: function(e){
if(this.successRedirect){
// How can I tell pagejs to redirect me ?
app.route = this.successRedirect;
}
}
});
</script>
Basically How do I tell pagejs (my routing library) to redirect the app to a page after a successful login ? My pagejs config lives in it's own routing.html file and I don't understand how to piece together all of this.
I hope someone will be abe to understand this broad question and hopefully help me.
Thanks
Short answer: Event Listeners. Place an event listener on your router. Have the login handler fire the event on the router. The router will pick up that event and then redirect.
...
_loginHandler: function(e){
if(this.successRedirect){
// How can I tell pagejs to redirect me ?
var router = document.querySelector('router');
router.dispatchEvent(new Event('redirect', {redirectURL: this.successRedirect});
app.route = this.successRedirect;
}
}
...
Then in your router:
connectedCallback() {
this.addEventListener('redirect', function(event) {
var url = event.redirectURL;
// Redirect using the router's API.
});
}

Can Polymer extend Electron's webview component?

In Electron (Atom-Shell), I'm trying to use Polymer 0.5 to extend Electron's webview tag (to add some custom attributes while retaining all of webview's methods). But I'm getting a NotSupportedError when I try to use my custom component. Is there a way to make this work?
Here's how I'm extending the webview:
<polymer-element name="my-webview" extends="webview">
<script>
Polymer({
// I'll add some custom attributes later
});
</script>
</polymer-element>
But when I try to use my-webview (either of these ways):
<my-webview src="http://example.com"></my-webview>
<webview is="my-webview" src="http://example.com"></webview>
...I get this error:
Uncaught NotSupportedError: Failed to execute 'registerElement' on
'Document': Registration failed for type 'my-webview'. The tag name
specified in 'extends' is a custom element name. Use inheritance
instead.
Now, it's true that Electron's webview is indeed a custom element. But Polymer happily extends other custom elements, right?
It seems like one problem might be that "webview" doesn't have a '-' in its name, so Polymer's findTypeExtension doesn't realize it's a custom element.
Is there any way to work around this and convince Polymer that webview needs to be extended through inheritance, like other custom elements?

Working with Polymer and requirejs

In an attempt to create polymer elements that use requirejs modules I ran into a blocking issue. I understand that polymer is not designed to work with requirejs, but for the time being It is my only option.
Searching for answers I found two solutions:
Don't use requirejs and make your modules compatible with HTML imports.
Put Polymer() call inside the requirejs callback as described here
Since I have to use require, at least for the time being, I went with the solution no.2. However, it turns out the solution causes asynchronous delays of element registration and incorrect data binding prior to Polymer upgrading the element.
Digging deeper into this issue, I started hacking undocumented Polymer internals with an intention to stop Polymer entirely until requirejs does its thing. Here is what I came up with:
Polymer.require = function(tag, deps, func) {
var stopper = {}
Polymer.queue.wait(stopper);
require(deps, function() {
delete stopper.__queue;
Polymer.queue.check();
Polymer(tag, func.apply(this, arguments));
});
};
I know this is terribly wrong. Is there a better solution?
I found that if I embed the call to require within the Polymer script I avoid this issue.
<link rel="import" href="../polymer/polymer.html"/>
<script src="../requirejs/require.js"></script>
<script src="../something/something.js"></script>
<polymer-element name="some-component">
<template>...</template>
<script>
(function() {
Polymer('some-component', {
someMethod: function () {
require(['something'], function (Something) {
var something = new Something();
...
}
}
)();
</script>
</polymer-element>
So there's this solution from Scott Miles but I find it a bit simplistic and inflexible as it relies on:
<script> tags to be executed in order, therefore ruling out:
async script tags
xhr based script loading
polymer getting loaded from a <script> tag, therefore:
layout.html and associated css won't be loaded
any future call to polymer.html won't be deduped
If you want more control over your bootstrapping logic you will need to enforce some amount of synchronisation between your components (which is what both requirejs and polymer are competing to do) before those are fully loaded.
The previous example is a more declarative (read polymer) way of doing things but falls short of fine grained tuning. I've started working on a repository to show how you can fully customise your load ordering, by using a more imperative approach where requirejs is given priority to orchestrate the rest of the bootstrapping.
At the time of writing, this extra control comes at the price of worse performance as the various scripts can't be loaded in parallel but I'm still working on optimising this.

Polymer: Registering Elements in External Scripts

In most of the examples I've seen for creating elements the script that registers the element is defined in the component's HTML file, e.g.
<link rel="import" href="/components/polymer/polymer.html">
<polymer-element name="my-element">
<template>
...
</template>
<script>
// convenience wrapper for document.registerElement
Polymer('my-element', {
...
});
</script>
</polymer-element>
It's possible to do that registration in an external script instead, e.g.
<script src="my-element.js"></script>
That seems like an attractive option because the script then becomes visible to tools like JSHint, but then you lose the automatically generated documentation of attributes, etc.
Is there a workflow or set of tools that help you get the best of both worlds?
e.g. combine a raw template and script into a single HTML file in a similar way to preprocessing CSS with Sass?
Yes. Polymer supports registering an element with by referencing an external script. See http://www.polymer-project.org/docs/polymer/polymer.html#separatescript. An original reason the element is in the call to Polymer() is to support this. It associates the definition with the script.