Comments (38)
that's actually expected and I've no idea why native would do that, if the node is not live.
Unfortunately there's also no way I am going to replace all DOM methods, getters, and setters, to support such edge/rare case, specially because I would need to place mutators in every DOM node.
There are ways to workaround this "issue", but I'd like to understand what's your use case.
from document-register-element.
Had the same issue I believe, that was during testing of Backbone views.
Testing of the is views is best done without adding them to the DOM for a
couple of reasons, mainly performance and ensuring isolation of code.
On Wed, May 13, 2015 at 7:02 PM, Andrea Giammarchi <[email protected]
wrote:
that's actually expected and I've no idea why native would do that, if the
node is not live.Unfortunately there's also no way I am going to replace all DOM methods,
getters, and setters, to support such edge/rare case, specially because I
would need to place mutators in every DOM node.There are ways to workaround this "issue", but I'd like to understand
what's your use case.—
Reply to this email directly or view it on GitHub
#21 (comment)
.
from document-register-element.
adding mutators to every node that is not live will kill real-world/production performance ... which one would you pick? ;-)
Like I've said, there are workarounds, like invoking createdCallback
manually after feature detecting that is not invoked otherwise, then you have the attached and detached that might not work as well.
Actually, I am not sure how native does when nodes are not live, regarding attribute changes and other two callbacks. If it's just a matter of asynchronous createdCallback invocation, then I might put back the ugly rAF/timer when nodes were created non live.
from document-register-element.
I believe they should be called no matter if the parent is live or not. The created callback at the very least would make sense, because the element did get just instantiated after all.
If you create a new instance with the constructor:
new MyElement()
// created
var div = document.createElement("div");
div.appendChild(new MyElement())
// created
// no attached callback was fired
but native calls the attached callback even outside the document too.
Real world use case:
There's a custom element which is being displayed periodically for the user. This element has an initial state that's need to be re-set every time it's shown, but the values of its state is dynamic each time. The element's state is managed with the element's API. The element can't be added to the DOM before it's re-set, but it can't be initialized outside of the DOM either, because the element's API is not available until it's inserted.
I understand the performance implications.
The quick and dirty workaround I used was to insert and immediately remove the element to and from the DOM so it gets initialized, because I didn't want to implement flags just for checking if the element is native or not.
So as I understand, until widespread native support, we have to keep this in mind.
from document-register-element.
do you know if webcomponents.js works as you would expect?
I need to double check the code because it was there and got removed at some point when somebody pointed out it should not have initialized the node if not live.
I also would like to understand if this is the entry point for problems: attribute changes without initialization, attached without having control over all possible node if not via overwrite of all possible methods in order to trigger checks, etc etc ... if it's as it is, it's a caveat that should be documented but a consistent one. Meaning until the node goes live, nothing happens.
This is IMO better than "just init happens" then nothing else work offline, what do you think?
from document-register-element.
also relevant ... since partially already discussed:
#15 (comment)
it turned out that innerHTML
overrides cause also tons of problems, so even fixing createElement
gotcha, it's hard to fix all the things that could happen via innerHTML
Moreover, innerHTML
is still used only because it's faster, wrapping it in not so fast/updatede browsers would result in perfromance problems.
IIRC Polymer had already faced performance issues with real world apps, I really would like to avoid to find this polyfill there too, and I'd like to understand if there's a design to improve in your logic.
What I mean is the following:
- why do you track and change states of nodes that might never been showed?
- why cannot you do the same and make the
createdCallback
the activator of the rest of the logic? - since you want to register offline nodes, why would you need an attachedCallback anyway?
Don't get me wrong, I understand this is how native behaves, but if there is an alternative, let's say webcomponents, that is closer to native but slower and bigger than this, I rather suggest developers that need offline features to move in there and leave a choice, instead of two slower, bigger, less compatible, more problematic, also identical polyfills.
https://github.com/WebComponents/webcomponentsjs
Thanks for your patience
from document-register-element.
I'll check webcomponents.js again today, but if I remember correctly I had the same issue there with attachedCallbacks not firing. But I'll take a look again later.
Regarding your questions about the design:
I think there sure are alternatives, and I'll look into them.
I'm happy that at least I have a better understanding of the situation.
- It might never shown, but the first time its shown, it needs to be initialized offline.
- The problem is that the element's api is not available at the time, not just createdCallback
- The attachedCallback may contain logic that initializes the element according to it's parent's state
Consider this:
document.registerElement('my-element', {
prototype: Object.create(
HTMLElement.prototype, {
createdCallback: {
value: function () {
// set default values..
}
},
attachedCallback: {
value: function () {
if (this.parentNode.hasAttribute("custom-attribute")) {
// set values depending on the parent's state
}
}
},
customApi: {
value: function (values) {
// set element's state dynamically
}
}
})
});
var div;
var myElement;
function showElement (dynamicValues) {
if (!div) {
// initialize a widget the first time it's requested
// save references because they won't change,
// just internal state like texts and attributes
div = document.createElement("div");
// imagine this is coming from a complex string template
div.innerHTML = "<span><my-element></my-element></span>";
myElement = div.getElementsByTagName("my-element")[0];
}
// set the state of the element according to dynamic values
// it's expected that the element has the custom API methods here
myElement.customApi(dynamicValues);
// insert the element into the dom
document.body.appendChild(div);
}
// when not needed, hide the element
function hideElement () {
if (div) {
div.remove();
}
}
I think consistency's better, even when it comes with limitations.
If overriding methods to provide this behavior would introduce performance drops I vote for a documented caveat + possible workarounds.
Thank you for your reply.
from document-register-element.
Wait a second ... if you put console.log
in the prototype you'll have this sequence on a natively supported browser: created
, custom
, attached
This means that attached
is indeed invoked only once the node is live, as specs say, not when is appended or created inside other nodes. This also means that your customApi
method does different things accordingly with the node parent attributes, as example, you might have surprises.
You are also probably trusting a synchronous createdCallback
which is not actually necessarily the case, specially when the polyfill uses observers to avoid performance issue, as discussed in the other bug I've liked before.
What I think is that you should detach custom API live interactions with the node itself if this has not been created, and eventually verify all the things at runtime when the live DOM knows the element.
This should not compromise your logic, and guard against polyfill with asynchronous behavior. Please bear in mind both polyfills and some early implementation might have an asynchronous behavior too so it's good to create components that react accordingly with these methods, and not the other way round.
As example, here is how I'd solve your problem if you really need to use innerHTML
// keep the custom element constructor reference
var MyElement = document.registerElement('my-element', {
prototype: Object.create(
HTMLElement.prototype, {
createdCallback: {
value: function () {
if (this._values) {
// do things values related
}
}
},
attachedCallback: {
value: function () {
if (this.parentNode.hasAttribute("custom-attribute")) {
// set values depending on the parent's state
}
}
},
customApi: {
value: function (values) {
this._values = values;
}
},
_values: {
writable: true,
value: null // or defaults values
}
})
});
var div;
var myElement;
function showElement (dynamicValues) {
if (!div) {
// initialize a widget the first time it's requested
// save references because they won't change,
// just internal state like texts and attributes
div = document.createElement("div");
// imagine this is coming from a complex string template
div.innerHTML = "<span><my-element></my-element></span>";
myElement = div.getElementsByTagName("my-element")[0];
}
// set the state of the element according to dynamic values
// it's expected that the element has the custom API methods here
// be sure the method is correct one through the prototype
MyElement.prototype.customApi.call(myElement, dynamicValues);
// insert the element into the dom
document.body.appendChild(div);
}
// when not needed, hide the element
function hideElement () {
if (div) {
div.remove();
}
}
Moreover
If you ditch innerHTML
when you create your DOM at runtime you would have the API directly exposed and the created
directly invoked.
document.registerElement('my-element', {
prototype: Object.create(
HTMLElement.prototype, {
createdCallback: {
value: function () {
console.log('created');
}
},
attachedCallback: {
value: function () {
console.log('attached');
if (this.parentNode.hasAttribute("custom-attribute")) {
// set values depending on the parent's state
}
}
},
customApi: {
value: function (values) {
console.log('custom');
}
}
})
});
var div;
var myElement;
function showElement (dynamicValues) {
if (!div) {
// initialize a widget the first time it's requested
// save references because they won't change,
// just internal state like texts and attributes
div = document.createElement("div");
// imagine this is coming from a complex string template
div.innerHTML = "<span><my-element></my-element></span>";
myElement = div.querySelector("my-element");
if (!myElement.customApi) {
myElement.replaceWith(
myElement = document.createElement('my-element')
);
}
}
// set the state of the element according to dynamic values
// it's expected that the element has the custom API methods here
myElement.customApi(dynamicValues);
// insert the element into the dom
document.body.appendChild(div);
}
// when not needed, hide the element
function hideElement () {
if (div) {
div.remove();
}
}
On non native browsers, this will log created
, custom
, and then attached
It's a workaround, but also a preferred solution compared to an innerHTML based one.
Please note that you can make the check generic via
function isCustomElement(el) {
return 'createdCallback' in el ||
'attachedCallback' in el ||
'detachedCallback' in el ||
'attributeChangedCallback' in el;
}
and verify with same code shown before ...
myElement = div.querySelector("my-element");
if (!isCustomElement(myElement)) {
myElement.replaceWith(
myElement = document.createElement('my-element')
);
}
About complex templates
This is the most tricky part and what you basically need is an array of registered elements, and an helper to set innerHTML
.
You might find better or more elegant solutions but this is the hint, you wrap upfront once document.registerElement
and you use innerHTML(el, html)
instead of el.innerHTML = html
.
// right after this poly, before any other script you have in place
var innerHTML = (function (document) {
// feature detect the problem
var
register = document.registerElement,
div = document.createElement('div'),
dre = 'document-register-element',
initialize,
registered
;
register.call(
document,
dre,
{prototype: Object.create(
HTMLElement.prototype,
{createdCallback: {value: Object}}
)}
);
div.innerHTML = '<' + dre + '></' + dre + '>';
// if natively supported, nothing to do
if (div.querySelector(dre).createdCallback) {
// return just an innerHTML wrap
return function (el, html) {
el.innerHTML = html;
return el;
};
}
// in other cases
registered = [];
initialize = function (el) {
if (
'createdCallback' in el ||
'attachedCallback' in el ||
'detachedCallback' in el ||
'attributeChangedCallback' in el
) return;
for (var
type = el.getAttribute('is'),
name = el.nodeName,
node = document.createElement.apply(
document,
type ? [name, type] : [name]
),
attributes = el.attributes,
i = 0,
length = attributes.length,
attr;
i < length; i++
) {
attr = attributes[i];
node.setAttribute(attr.name, attr.value);
}
el.replaceWith(node);
};
// augment the document.registerElement method
document.registerElement = function registerElement(name, info) {
var type = info.extends;
name = (type ? (type + '[is=' + name + ']') : name).toLowerCase();
if (registered.indexOf(name) < 0) registered.push(name);
return register.apply(document, arguments);
};
return function (el, html) {
el.innerHTML = html;
registered.forEach.call(
el.querySelectorAll(
registered.join(',')
),
initialize
);
return el;
};
}(document));
Now we've gone full circle, and we can go back to your initial example just changing one switch.
document.registerElement('my-element', {
prototype: Object.create(
HTMLElement.prototype, {
createdCallback: {
value: function () {
console.log('created');
}
},
attachedCallback: {
value: function () {
console.log('attached');
if (this.parentNode.hasAttribute("custom-attribute")) {
// set values depending on the parent's state
}
}
},
customApi: {
value: function (values) {
console.log('custom');
// set element's state dynamically
}
}
})
});
var div;
var myElement;
function showElement (dynamicValues) {
if (!div) {
// initialize a widget the first time it's requested
// save references because they won't change,
// just internal state like texts and attributes
div = document.createElement("div");
// imagine this is coming from a complex string template
innerHTML(div, "<span><my-element></my-element></span>"); // <=== there !
myElement = div.getElementsByTagName("my-element")[0];
}
// set the state of the element according to dynamic values
// it's expected that the element has the custom API methods here
myElement.customApi(dynamicValues);
// insert the element into the dom
document.body.appendChild(div);
}
The result will be identical in both native and polyfilled.
I hope this helps at least a little bit.
from document-register-element.
Not just a little bit! I really appreciate your effort.
Wrapping innerHTML into a helper and patching elements is clever. I can go on with it from here.
Also, your suggestion not to rely on synchronous callbacks is a good warning too.
Thanks for the reply and the workaround solution!
from document-register-element.
Please have a look at the new README, specifically this section related to a better and tested version of the function I've written in here.
Full helper source code and its minified version
Once again that should be placed after the poly, and before the rest of the logic.
Here new tests and please note Webkit based browsers will invoke createdCallback
asynchronously, be carefull with custom APIs used before an element has been created.
If this works, please close this bug as it will remain, at this point, a won't fix.
from document-register-element.
@tunderdomb I havent tried it but it should work:
var docfrag = document.createDocumentFragment();
var myElement = document.createElement("my-element");
docfrag.appendChild(myElement);
// created
// attached
from document-register-element.
Checked webcomponents.js, does the same thing; same problem: not calling callbacks outside the DOM.
A note regarding attachedCallback
:
Unless specified otherwise, this callback must be enqueued whenever custom element is inserted into a document and this document has a browsing context.
Yes, it doesn't say it should be called on offline nodes.
I tried the innerHTML helper, and found two issues with it:
replaceWith
is not a standard method- innerHTML doesn't handle nested custom elements
<custom-element>
<another-element>
<span></span>
</another-element>
</custom-element>
The helper you provided creates a new element for every custom element it finds in the string provided (node = document.createElement.apply
). It ignores the innerHTML of those elements. In the above example the innerHTML value of the newly created node
will be empty. But it should contain a span. Also, if you run it on the above string template, it returns an empty custom-element
too, which should contain another custom element with a span.
So I tweaked it a little and added recursion to it.
Didn't find contribution notes in the readme, so I paste it here, but if you'd prefer a pr I'd do that too when I find time for it.
var
register = document.registerElement,
div = document.createElement('div'),
dre = 'document-register-element',
innerHTML = register.innerHTML,
initialize,
registered
;
// avoid duplicated wrappers
if (innerHTML) return innerHTML;
// feature detect the problem
register.call(
document,
dre,
{prototype: Object.create(
HTMLElement.prototype,
{createdCallback: {value: Object}}
)}
);
div.innerHTML = '<' + dre + '></' + dre + '>';
// if natively supported, nothing to do
if ('createdCallback' in div.querySelector(dre)) {
// return just an innerHTML wrap
return (register.innerHTML = function (el, html) {
el.innerHTML = html;
return el;
});
}
// in other cases
registered = [];
initialize = function (el) {
if (
'createdCallback' in el ||
'attachedCallback' in el ||
'detachedCallback' in el ||
'attributeChangedCallback' in el
) return;
for (var
type = el.getAttribute('is'),
name = el.nodeName,
node = document.createElement.apply(
document,
type ? [name, type] : [name]
),
attributes = el.attributes,
i = 0,
length = attributes.length,
attr;
i < length; i++
) {
attr = attributes[i];
node.setAttribute(attr.name, attr.value);
}
// run the createdCallback so it can work with the correct attributes
node.createdCallback();
// initialize children too
innerHTML(node, el.innerHTML);
// swap nodes
el.parentNode.replaceChild(node, el);
};
innerHTML = function (el, html) {
el.innerHTML = html;
var children = el.children;
var i = -1;
var l = children.length;
while (++i < l) {
if (registered.indexOf(children[i].nodeName.toLocaleLowerCase()) !== -1) {
initialize(children[i])
}
}
return el;
};
var registerElement = function(type, options) {
var name = (options.extends ?
(options.extends + '[is="' + type + '"]') : type
).toLowerCase();
if (registered.indexOf(name) < 0) registered.push(name);
return register.apply(document, arguments);
};
document.registerElement = registerElement;
// augment the document.registerElement method
registerElement.innerHTML = innerHTML;
from document-register-element.
replaceWith
is not a standard method
it is standard, and there's more standard you might want to use (like append
, that's new DOM4 stuff too)
I use dom4 since quite ever, I strongly suggest you to do the same. Tests have it in too.
I should probably specify it as dependency or maybe just use replaceChild
, but I believe if you want to use Custom Elements you want to use modern DOM in all its glory.
innerHTML doesn't handle nested custom elements
I'll check that ... your code won't work anyway, there are 2 ways to register elements, via node name and via extends.
Please read more about this here:
https://github.com/WebReflection/document-register-element#htmltablerowinputselectotherselement
Thanks for the report
from document-register-element.
Sorry about that, I just noticed that it was undefined in Chrome, so immediately assumed it wasn't standard. My apologies.
With the modifications I did, it worked for me. Elements registered correctly, even a template with nested custom elements. Anyway, thank you for your suggestion, it helped me a great deal.
from document-register-element.
it won't work if you have <input is="x-date">
as example, 'casue nodeName will be input, but you register x-date
instead ;-)
I'll have a look as soon as I can and try to figure out how to solve "all the things"
Cheers
from document-register-element.
Now that I didn't try, and you're right it won't work.
The loop might check for the is
attribute of the node at hand, and use it to see if it's a registered custom element. Like:
if (
registered.indexOf(children[i].nodeName.toLowerCase()) !== -1
|| (registered.indexOf(children[i].getAttribute("is")||"").toLowerCase() !== -1
) {
initialize(children[i])
}
Just improvised.
"All the thing" shall come when browsers implement standards :3
from document-register-element.
so, I haven't pushed/bumped new version yet, but could you please verify the current innerHTML.js version works as expected? (there's still need for dom4 here, but nested nodes should be just fine)
from document-register-element.
Is this really standard (innerHTML/NestedElements/createdCallback/etc) ? where the specified?
from document-register-element.
@SerkanSipahi I am not sure I understand your question ... innerHTML
is a helper function to avoid problems when you use innerHTML
instead of creating nodes via DOM.
Nested elements is something that needs to be solved within the helper.
createdCallback
is part of Custom Elements standard together with others
from document-register-element.
@WebReflection Thanks so much for providing the innerHTML workaround. Would you please bump up the version with the newest fix so that we could point to that?
from document-register-element.
@WebReflection Thanks for you quick response! However, when we were trying to use the innerHTML function, there is an error "el.replaceWith is not a function". Do you have any idea on what is causing that? Thanks!
from document-register-element.
you should upgrade your DOM ... and I should mention this somewhere
from document-register-element.
actually, you know what? never mind, I've updated using good old replaceChild
instead, however I still strongly suggest you to upgrade your DOM ;-)
from document-register-element.
@WebReflection Thanks. And another question, we notice that the sequence is a little different. In this innerHTML function, the createdCallback function is called before binding the attributes. Our tests are failing since we are testing in createdCallback whether the attributes have already been bound. And in Chrome, looks like it also binds the attributes first. Any thoughts on that?
from document-register-element.
not sure I udnerstand what you mean ... if it's not created, how can it has attributes? any little example to verify?
from document-register-element.
OK @smilland I see what you mean ... so here the thing: in order to copy over attributes I need a node. In order to have a node I need to create one and when I create a node, the createdCallback
triggers.
For the current logic it's expected, but I understand is not ideal in your case because you expect everything to be there.
Please bear in mind this innerHTML
helper is some sort of "magic wrap" but the underlying logic is not touched. These are two different files indeed, and I need to think carefully how to do what you expect without causing troubles to the rest of the logic that is not based to innerHTML
Meanwhile, I wonder if in your case you could simply move the attributes related logic to attachedCallback
instead of createdCallback
as temporary work around until we find a better solution?
from document-register-element.
I believe 0.3.5
should work as expected ... is a bit hacky solution, but this whole poly is some sort of big hack so probably I won't care much. Please let me know if latest works, thanks.
from document-register-element.
P.S. you need to update both files, document-register-element
and innerHTML
from document-register-element.
Thanks so much for all your help. We tried it out, it definitely works! We appreciate all your efforts.
from document-register-element.
no problem ... btw, who is "we", if I might? :-)
from document-register-element.
added enhancement label, will close still as won't fix since I've provided a work around. Feel free to reopen if you find something wrong. Will try to push again to the CDN so 0.3.6
will have everything in.
Cheers
from document-register-element.
@WebReflection What's the difference between appendChild
and append
from DOM4?
from document-register-element.
It's in standards , append accepts strings too and doesn't return the
appended child. WebKit has it already
On Sunday, 11 September 2016, Joseph Orbegoso Pea [email protected]
wrote:
@WebReflection https://github.com/WebReflection What's the difference
between appendChild and append from DOM4?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#21 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAFO9Y-PvCtPoXJXYqnJym4FU7LG3RfEks5qpGLWgaJpZM4EZYEI
.
from document-register-element.
So it's effectively the same as innerHTML and appendChild combined into a single shortcut method. Cool!
Not returning the child could possibly be unhelpful in the case of strings. Would be nice to do like jQuery:
let div = someEl.append('<div>blah</div>')
console.log(div.innerHTML) // blah
from document-register-element.
That's not what specs were written. It's not going to change.
On Wednesday, 14 September 2016, Joseph Orbegoso Pea <
[email protected]> wrote:
So it's effectively the same as innerHTML and appendChild combined into a
single shortcut method. Cool!Not returning the child could possibly be unhelpful in the case of
strings. Would be nice to do like jQuery:let div = someEl.append('
blah')console.log(div.innerHTML) // blah—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#21 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAFO9eLnmGBTlG_wRTKgQFTHeuV0pSvdks5qp1yfgaJpZM4EZYEI
.
from document-register-element.
BTW, append()
is more like appendChild
and textContent
, not innerHTML
You should've tried it first ;-)
It use to be on specs, it has been put on hold but it shipped regardless in WebKit so it's already adopted.
This, together with prepend
and remove
, replaceWith
, before
and after
from document-register-element.
What's the advantage of having both appendChild
and append
? When would we rather use append than appendChild?
from document-register-element.
legacy will keep appendChild
around forever. Other shortcuts have been around for years but for some reason commented out recently.
DOM4 poly, for legacy reasons, won't drop these. You can use whatever you want if dom4 is included.
Bear in mind this is CustomElements polyfill, not the DOM4 one.
from document-register-element.
Related Issues (20)
- LifeCycle events order of nested custom elements inconsistent across Chrome and Firefox HOT 18
- Built-in elements don't work in Firefox HOT 6
- TypeError: new.target does not define a custom element HOT 3
- document.registerElement is deprecated and will be removed in M73 HOT 3
- Post-install script slowness HOT 3
- appreciate your feedback for custom element diagram HOT 8
- [Uncaught DOMException: Failed to execute 'registerElement' on 'Document'] when used in Chrome Extension HOT 16
- Functions are not evaluated in connectedCallback HOT 1
- `this` reference in contructor broken HOT 14
- Multiple instances of the polyfill leads to unexpected behaviour HOT 1
- error ""Failed to construct 'HTMLElement': Please use the 'new' operator"" when using with Angular/elements 8.2.0 HOT 2
- Refreshing a document inside an iframe which loads d-r-e breaks the polyfill and leaves document.createElement as undefined HOT 15
- `attributeChangedCallback()` bound value is invalid HOT 15
- Add DRE to Polyfill.io service HOT 1
- [QUESTION] Unable to get property '_isMounted' of undefiened. HOT 1
- TypeError - Object doesn't support property or method 'registerElement' HOT 3
- Time to compare again? (webcompents/custom-elements) HOT 2
- Polyfill does not seem to be working in IE 11 HOT 6
- postinstall fails in noexec enviornment HOT 1
- We unable to install latest version @1.14.7 HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from document-register-element.