how to use Polymer polyfills together - javascript

I'm trying to use the Polymer polyfills for ShadowDOM and Custom Elements
If I use them individually, they work well, but when I use both at the same time I get errors like this
Uncaught TypeError: Cannot read property 'polymerShadowRoot_' of undefined.....Element.js:69
It depends whether I first include customelement.js or shadowdom.js
Here is my test code:
<!doctype html>
<html>
<head>
<script src="/bower_components/CustomElements/custom-elements.js"></script>
<script src="/bower_components/ShadowDOM/shadowdom.js"></script>
<script>
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
console.log('create shadowDOM');
var root = this.createShadowRoot();
root.innerHTML = '<content></content>';
};
document.register('x-foo', {prototype: proto});
</script>
</head>
<body>
<x-foo><span>hallo</span></x-foo>
</body>
</html>
Any suggestions what might go wrong here ?

Whenever using ShadowDOM polyfill, you must load it first because it utterly remaps DOM. Other libraries (generally) can load on top of the remapping, but not underneath.
http://jsbin.com/uBOQIBu/3/edit

Related

How to use javascript module on an HTML page in a second inline script

I have a JavaScript module mymmodule.js exporting a list:
export var mylist = ['Hallo', 'duda'];
Normally this module is used in other modules and this works fine. But additionally I want to use the export(s) of the module as-is in an inline script on an HTML page. I tried to copy the exports to the window object:
<html>
<head>
<script type="module">import * as mm from './mymodule.js'; window.mm = mm;</script>
</head>
<h1>MyMain</h1>
<p>
<div id = "info">...</div>
</p>
<script type="text/javascript">
document.getElementById('info').textContent = window.mm.mylist;
</script>
</html>
but I get the error "window.mm is undefined" in the console. I tried referencing mm.mylist instead of window.mm.mylist with no better result.
How can I reference the exports of a module in a second inline script on the HTML page?
The problem is that modules are execute at the same stage as pscripts with the defer attribute](https://javascript.info/script-async-defer#defer), i.e. after reading the page and executing JavaScript in script tags.
Therefore, when the browser sees
document.getElementById('info').textContent = mm.mylist
the mymodule.js script hasn't been executed and the mm object is not available yet.
To mitigate this you need to run code referencing exports from mymodule after the DOM is completely loaded, e.g. in the onload event:
<html>
<head>
<script type="module">import * as mm from './mymodule.js'; window.mm = mm;</script>
</head>
<h1>MyMain</h1>
<p>
<div id = "info">...</div>
</p>
<script type="text/javascript">
window.onload = function() {
document.getElementById('info').textContent = mm.mylist;
}
</script>
</html>

Create custom elements v1 in ES5, not ES6

Right now, if you follow the exact specifications of v1 of the custom elements spec, it's not possible to use custom elements in browsers that don't support classes.
Is there a way to create v1 custom elements without using the class syntax so that they are fully functional in Chrome, FireFox and IE11. Also, since IE11 doesn't have native support for custom elements, I'm assuming we will probably need to use some pollyfills, so what polyfills or libraries do we need in order to make this work in IE11?
I've messed around with Polymer 2, Polymer 3, and Stencil, but they are all a bit heavy-duty for some of the things we want to create.
This question seems to be on the right track, but I had some trouble getting it to work in IE11, so also how can I use Reflect.construct in IE11 for the purposes of custom elements?
Here's a full example of writing ES5-compatible custom elements using the v1 spec (credit to this comment on github)
<html>
<head>
<!--pollyfill Reflect for "older" browsers-->
<script src="https://cdn.rawgit.com/paulmillr/es6-shim/master/es6-shim.min.js"></script>
<!--pollyfill custom elements for "older" browsers-->
<script src="https://cdn.rawgit.com/webcomponents/custom-elements/master/custom-elements.min.js"></script>
<script type="text/javascript">
function MyEl() {
return Reflect.construct(HTMLElement, [], this.constructor);
}
MyEl.prototype = Object.create(HTMLElement.prototype);
MyEl.prototype.constructor = MyEl;
Object.setPrototypeOf(MyEl, HTMLElement);
MyEl.prototype.connectedCallback = function() {
this.innerHTML = 'Hello world';
};
customElements.define('my-el', MyEl);
</script>
</head>
<body>
<my-el></my-el>
</body>
</html>
Also, for the typescript lovers, here's a way to write custom elements using typescript that will still work when compiled to ES5.
<html>
<head>
<!--pollyfill Reflect for "older" browsers-->
<script src="https://cdn.rawgit.com/paulmillr/es6-shim/master/es6-shim.min.js"></script>
<!--pollyfill custom elements for "older" browsers-->
<script src="https://cdn.rawgit.com/webcomponents/custom-elements/master/custom-elements.min.js"></script>
<script type="text/typescript">
class MyEl extends HTMLElement{
constructor(){
return Reflect.construct(HTMLElement, [], this.constructor);
}
connectedCallback () {
this.innerHTML = 'Hello world';
}
}
customElements.define('my-el', MyEl);
</script>
</head>
<body>
<my-el></my-el>
<!-- include an in-browser typescript compiler just for this example -->
<script src="https://rawgit.com/Microsoft/TypeScript/master/lib/typescriptServices.js"></script>
<script src="https://rawgit.com/basarat/typescript-script/master/transpiler.js"></script>
</body>
</html>

Create and Use a Custom HTML Component?

I have the following local html:
<html>
<head>
<link rel="import" href="https://mygithub.github.io/webcomponent/">
</head>
<body>
<!-- This is the custom html component I attempted to create -->
<img-slider></img-slider>
</body>
</html>
and the following attempt at a template:
<template>
<style>
.redColor{
background-color:red;
}
</style>
<div class = "redColor">The sky is blue</div>
</template>
<script>
// Grab our template full of slider markup and styles
var tmpl = document.querySelector('template');
// Create a prototype for a new element that extends HTMLElement
var ImgSliderProto = Object.create(HTMLElement.prototype);
// Setup our Shadow DOM and clone the template
ImgSliderProto.createdCallback = function() {
var root = this.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true));
};
// Register our new element
var ImgSlider = document.registerElement('img-slider', {
prototype: ImgSliderProto
});
</script>
As described in this article. When I run the code, I get:
Uncaught TypeError: Cannot read property 'content' of null
at HTMLElement.ImgSliderProto.createdCallback ((index):20)
In other words document.querySelector('template'); returns null. What gives?
My goal is to create custom html element and display it on the website that links the template code. I am 100% sure I am pulling the remote template code correctly (obviously, since I get the error in that code).
P.S. I am using latest Chrome, so I shouldn't need polyfills.
Try this:
var tmpl = (document.currentScript||document._currentScript).ownerDocument.querySelector('template');
The problem you ran into is that the template isn't really part of document but it is part of the currentScript. Due to polyfills and browser differences you need to check for currentScript and _currentScript to work correctly.
Also be aware that HTML Imports will never be fully cross browser. Most web components are moving to JavaScript based code and will be loaded using ES6 module loading.
There are things that help create templates in JS files. Using the backtick (`) is a reasonable way:
var tmpl = document.createElement('template');
tmpl.innerHTML = `<style>
.redColor{
background-color:red;
}
</style>
<div class = "redColor">The sky is blue</div>`;

WebODF simple file open

I'm trying to make a simple file viewing with WebODF in javascript.
My code looks like this:
<head>
<script src="webodf.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
function init() {
var odfelement = document.getElementById("odf"),
odfcanvas = new odf.OdfCanvas(odfelement);
odfcanvas.load("c:\file directory\myfile.odt");
}
window.setTimeout(init, 0);
</script>
</head>
When I'm running the code I'm getting an alert:
ASSERTION FAILED: odf.OdfCanvas constructor needs DOM element
Why is that happening and how can I open the odt file?
I think the error means you need to create a div or section with id =odf and that webodf is unable to find a Dom element. Or you can create a element using document.createElement() and pass that as input to webodf.
You can refer to this answer

custom attributes in a script tag

Can I use a custom attribute in a script tag such as:
<script type="text/javascript" mycustomattribute="foo">
// JavaScript
</script>
And then use the contained JavaScript to access the value of mycustomattribute?
Can I use a custom attribute in a script tag such as:
Yes, using data-* attributes:
<script data-info="the information"...
And then use the contained javascript to access the value of 'mycustomattribute'?
Yes, probably. If you give the script tag an id, you can do it reliably:
var info = document.getElementById("theId").getAttribute("data-info");
Otherwise, you have to make assumptions about the script tag. If it's always in the markup of the page (not added later using code), you can do this:
var scripts = document.getElementsByTagName("script");
var info = scripts[scripts.length - 1].getAttribute("data-info");
That's because if the script tag is in the markup, it's run as soon as it's encountered (unless async or defer is used [and supported by the browser]), and will always be the last script tag on the page (at that point in time). But again, if code adds the script tag later, using createElement and appendChild or similar, you can't rely on that.
Here's a complete example: Live Copy
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Data on Script Tags</title>
</head>
<body>
<script>
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
</script>
<script data-info="first">
(function() {
var scripts = document.getElementsByTagName("script");
var info = scripts[scripts.length - 1].getAttribute("data-info");
display("Got info '" + info + "'");
})();
</script>
<script data-info="second">
(function() {
var scripts = document.getElementsByTagName("script");
var info = scripts[scripts.length - 1].getAttribute("data-info");
display("Got info '" + info + "'");
})();
</script>
</body>
</html>
Yes, you can do this. Browsers are required to ignore attributes they don't recognize in any tag (to allow for graceful degradation when a document uses new features with an old browser).
However, it would be better to use a dataset tag, since these are explicitly reserved for users, so they don't conflict with future HTML changes.
<script id="myscript" type="text/javascript" data-mycustomattribute="foo">
You can then access this either using an ordinary attribute accessor:
document.getElementById("myscript").getAttribute("mycustomattribute")
or with the dataset API:
document.getElementById("myscript").dataset.mycustomattribute
(but see the browser compatibility table in the documentation).
You should be able to get it using jquery
$("script").attr("mycustomattribute");
Or try this using regular JavaScript
document.getElementsByTagName("script")[0].getAttribute("mycustomattribute");
Might bake sense to give a script tag an id to be able to do this
document.getElementById("someId").getAttribute("mycustomattribute");
I built a library for this very instance and it's quite easy to use:
<script id="your-library" src="./your-library.js" data-car="pagani" data-star-repo="yes, please :)">
and then you can get that data:
/**
* This returns the following:
*
* {
* car: 'pagani',
* starRepo: 'yes, please :)'
* }
*/
ScriptTagData.getData('your-library');
/**
* This returns the juust <script> tag
*/
ScriptTagData.getData('your-library');
You can download it via Bower, CDN or just take the code: https://github.com/FarhadG/script-tag-data

Categories

Resources