korynunn / crel Goto Github PK
View Code? Open in Web Editor NEWa small, simple, and fast DOM creation utility
License: MIT License
a small, simple, and fast DOM creation utility
License: MIT License
Hi there, I love your work with crel. I think I found a bug.
Testing in IE8 made me find the bug in this line:
var isNode = typeof Node === 'object'
? function (object) { return object instanceof Node }
try running this code in any browser's console:
var a = new Object();
var b = new Object();
a instanceof b;
you'll get an error saying that the expected operand is a function. A constructor, to be precise. Your code checks if Node is an object and then does an instanceof Node check with it. So it cannot ever by a function. Here's the code that fixes it:
return object instanceof Node.constructor
Sorry, I did not fork & commit this fix. I want you to see the problem and decide if I was right or I just misinterpreted something.
It would be very nice to have #hash-like
id and .dot-like
classes parsed on tag string.
Eg.:
crel(document.body,
crel('input.cool'),
crel('button#login')
);
I'm generating SVGs with javascript alongside my HTML generation. Currently I can't use crel for the SVG elements, because they must be created with document.createElementNS
.
Would there be any chance of some feature creep to the API so I can use crel for all my javascript element creation? Maybe something like
crelNS('svg', 'svg', {'class': 'graph', 'height': 100, 'width': 200},
crelNS('svg', 'g', {'class': 'legend', 'x': 70, 'y': 40},
crelNS('svg', 'text', 'hello')));
or perhaps
crel.svg('svg', {'class': 'graph', 'height': 100, 'width': 200},
crel.svg('g', {'class': 'legend', 'x': 70, 'y': 40},
crel.svg('text', 'hello')));
I'd be happy to create a pull request for this feature.
crel is fast. Depending on what browser you use, it is up there with straight document.createElement calls.
That part of the README seems to date back to 2012, the jsperf link is dead because jsperf is dead, so I can't really see the numbers there.
I've been fixing performance in FRZR and RE:DOM lately, and I'm writing my own little DOM library for personal uses / research, and out of curiosity I run crel through a small benchmark of mine.
Relevant numbers:
Benching Vanilla JS <div> with children
5103ns per iteration (195962 ops/sec)
Benching Crel <div> with children
19319ns per iteration (51762 ops/sec)
Relevant codes:
bench('Vanilla JS <div> with children', function() {
var div = document.createElement('div');
var header = document.createElement('h1');
header.className = 'voo-header';
var b = document.createElement('b');
b.textContent = 'Voo';
header.textContent = 'Hello ';
header.appendChild(b);
header.appendChild(document.createTextNode('!'));
div.appendChild(header);
var p = document.createElement('p');
p.textContent = 'Bacon ipsum dolor amet meatloaf meatball shank porchetta \
picanha bresaola short loin short ribs capicola fatback beef \
ribs corned beef ham hock.';
div.appendChild(p);
});
bench('Crel <div> with children', function() {
crel('div',
crel('h1', { className: 'crel' }, 'Hello ', crel('b', 'Voo'), '!'),
crel('p',
'Bacon ipsum dolor amet meatloaf meatball shank porchetta \
picanha bresaola short loin short ribs capicola fatback beef \
ribs corned beef ham hock.'
)
)
});
Given what crel
does, and all my various experiments, numbers closer to 7000-8000ns on my hardware should have been expected. Are you interested in PRs trimming some of the unnecessary overhead?
Patch 5414591 removes the check for Proxy
support, breaking this library on IE11. Was the goal here just to save a single line of code? Could we maybe revert it?
this is essential info for your readme
Lets say I have a message string which I want to detect for URLs and enclose them in anchor tags. This full message is then placed within a div element using crel.
Let's say our message is "http://foo.com" and the desired result should be enclosed within an anchor tag. The following line is similar to what I am currently doing:
msg.replace(exp, crel('a', {href: '$1', target: '_BLANK', class: 'foo'}, '$1'));
The outcome of this would not be an anchor tag, but rather it would be the normal URL found prepended by the current page URL. For instance if my page was "http://localhost/" then the string returned would be "http://localhost/http://foo.com"
I believe the $1 is being interpreted as something else within the library itself. I'm not 100% sure if it's a bug but it's something I came across and cannot figure out a work-around. I was originally using a full string such as:
msg.replace(exp,'<a href="$1" target="_BLANK" class="foo">$1</a>');
This itself works fine if I was not appending to an element using crel. The crel replica as mentioned above, causes other issues.
Apparently the previous edit is somewhat inaccurate. Take the following code for example
var msg = "http://foo.com";
var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
var html = crel('a', {href: '$1', target: '_BLANK', class: 'foo'}, '$1');
console.log(html);
console.log(msg.replace(exp, html));
console.log(msg.replace(exp,'<a href="$1" target="_BLANK" class="foo">$1</a>'));
The result would be this:
<a href="$1" target="_BLANK" class="foo">$1</a>
http://localhost:6022/http://foo.com
<a href="http://foo.com" target="_BLANK" class="foo">http://foo.com</a>
The last one is my desired result. Somehow crel is creating the right elements, but when used with .replace it will act strangely. I still believe it's a possible bug with crel though.
I've modified how the replace works and I ended up with something different. The following code:
msg.replace(exp, function(match) {
console.log(crel('a', {href: match, target: '_BLANK', class: 'foo'}, match));
});
Will produce:
<a href="http://foo.com" target="_BLANK" class="foo">http://foo.com
This itself looks fairly accurate. Now if I was to use that as the return for the replace:
return msg.replace(exp, function(match) {
return crel('a', {href: match, target: '_BLANK', class: 'foo'}, match);
});
Then when it appends to the element, then output will not be an anchor tag at all but rather the output would be "http://foo.com/" (notice the forward slash).
How I append to the element is rather simple. I use the following code (data.text would be the message in question and parseUrls is the function containing all the above):
crel(messageContainer,
crel('div', parseUrls(data.text))
);
I believe what needs to happen is the string needs to be split up as I believe crel returns a document.createElement, and even if I was to grab that innerHTML then when I append it to the container, it will escape it.
So based off of this, it may not be an actual bug but rather it is an issue I cannot figure out a work-around for.
Really think crel should be available in npm - ship it :)
It would be great for those that need to link to this lib in the page, to be able to use a CDN such as cdnjs and then use a local fallback by checking if the global exists. Cheers.
Hi there, first of all crel is awesome and been using it for ages without any problems.
I just updated to crel 2.2.0
in a project using Babel 6 with es2015 and stage-3 presets, and am getting the following weird behaviour:
crel('div')
// --> <default>div</default>
crel('div', {'class': 'abc'})
// --> <default>"div""[object Object]"</default>
I don't know how to begin debugging this because I forked crel and ran npm test
and all tests passed... I guess this must have to do with the new Proxy API support because that's the only major thing that's changed since 2.1.8
, which works fine. Any pointers? Thanks!
If you put an iframe on a page and do a little something like this:
var innerBody = document.getElementsByTagName("iframe")[0].contentDocument.body;
crel(innerBody, crel("h1", "hi"))
In Chrome 72, it will error with
Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('[object HTMLBodyElement]') is not a valid name.
(It succeeds without issue in Firefox 65.)
This is due to the check where crel is trying to figure out if its argument is a node or not (see related issue #11).
In Chrome
I expect this is an uncommon edge case, and I very much appreciate crel's dedication to keeping its implementation compact and interface simple, so I'd understand if this is a wontfix, but I figured it's worth documenting.
If we do want to fix this, I think the thing to do is provide a way to change which window
crel uses to get Element
and Node
and document
.
(Perhaps surprisingly, doing innerBody.appendChild
does work with elements created using the outer document. At least with these two specific browser versions and document types. But I expect it would be safer, and easier to pass type checks, if the createElement
were called on the document the elements are intended to be appended to.)
Hello, just started dabbling with crel. Thanks - great tool.
Just wondering if anyone has made a utility to convert html to crel code.
I have a few views I'd like to try and convert.
Was looking at this http://www.jsonml.org/, which seems to be a good start;
Hope I'm not trying to reinvent the wheel here.
How do you use attributes that use - in it? Like data-id? I get an error saying the crel javascript does not know how to handle that.
Anyone know?
Please add changelog or release notes to the repo!
Thanks for the hard work.
There's no mention of this in the readme, even tho it's a really useful feature.
Proxy mechanism is very convenient but I did not find a way to create tags with a dash, e.g. <my-table></my-table>
. It would be convenient to use camelCase (as seen in css-loader) to proxy crel using crelProxy.myTable()
over crelProxy['my-table']
.
I could make a PR but somehow my editor (atom/vscode) changes white spaces and the whole file is marked as a change:
https://github.com/quirm/crel/commit/acb0c89b5660498d8b0f330331be47890dcab94d (a change https://github.com/quirm/crel/blob/master/crel.js#L159-L164)
On Chrome at least (only tested that so far), the following works fine:
valueEdit = crel('input', {
type: 'text'
});
valueEdit.onblur=function(){console.log('zzz');};
However, this one returns an error Uncaught SyntaxError: Unexpected token (
line 1:
valueEdit = crel('input', {
type: 'text',
onblur: function(){console.log('zzz');}
});
Many events (like onclick) work fine, but not the others. Interestingly, the Chrome debugger shows onblur: undefined
in the non-working case, whereas it is obviously correctly referring to an anonymous function in the working case.
Is this a crel bug?
Actually the jsperf is not quite correct comparence of pure .innerHTML to your solution. Because in your and some others case, you have references to the dom nodes. Which means after .innerHTML you need to find references, which also costs time. I would love to see a bench like that.
Not sure if this is something you want to add Kory, but I just found myself trying to do this (mainly to see if it would work):
crel('div', {
class: 'blah',
data: {
caption: 'A Test caption'
}
});
To see if the HTML element generated would contain a data-caption
attribute. Might be a nice feature to add at some stage if it doesn't increase the size of crel too much. Also, I can't remember if you mentioned that someone had already implemented this in another fork somewhere...
Hi there I needed to integrate your utility into one of my projects and I converted it to typescript. This is what i have done so far in case you want to offer this version too:
export class Crel {
private static fn: string = 'function';
private static obj: string = 'object';
private static nodeType: string = 'nodeType';
private static textContent: string = 'textContent';
private static setAttribute: string = 'setAttribute';
private static attrMapString: string = 'attrMap';
private static d: Document = typeof document === Crel.obj ? document : <Document>{};
public create(ele: any, ...params: any[]): any {
var args = arguments, //Note: assigned to a variable to assist compilers. Saves about 40 bytes in closure compiler. Has negligable effect on performance.
element = args[0],
child: any,
settings = args[1],
childIndex = 2,
argumentsLength = args.length,
attributeMap = Crel.attrMapString;
element = this.isElement(element) ? element : Crel.d.createElement(element);
// shortcut
if (argumentsLength === 1) {
return element;
}
if (!this.isType(settings, Crel.obj) || this.isNode(settings) || this.isArray(settings)) {
--childIndex;
settings = null;
}
// shortcut if there is only one child that is a string
if ((argumentsLength - childIndex) === 1
&& this.isType(args[childIndex], 'string')
&& element[Crel.textContent] !== undefined) {
element[Crel.textContent] = args[childIndex];
} else {
for (; childIndex < argumentsLength; ++childIndex) {
child = args[childIndex];
if (child == null) {
continue;
}
if (this.isArray(child)) {
for (var i = 0; i < child.length; ++i) {
this.appendChild(element, child[i]);
}
} else {
this.appendChild(element, child);
}
}
}
for (var key in settings) {
if (!attributeMap[key]) {
element[Crel.setAttribute](key, settings[key]);
} else {
var attr = attributeMap[key];
if (typeof attr === Crel.fn) {
attr(element, settings[key]);
} else {
element[Crel.setAttribute](attr, settings[key]);
}
}
}
return element;
}
private isType(a: any, type: any) {
return typeof a === type;
};
private isNode(object: any) {
if (Node === Crel.fn) {
return object instanceof Node;
}
return object &&
this.isType(object, Crel.obj) &&
(Crel.nodeType in object) &&
this.isType(object.ownerDocument, Crel.obj);
}
// in IE <= 8 Node is an object, obviously..
private isElement(object: any): any {
return this.isNode(object) && object[Crel.nodeType] === 1;
}
private isArray(a: any) {
return a instanceof Array;
}
private appendChild(element: any, child: any) {
if (!this.isNode(child)) {
child = Crel.d.createTextNode(child);
}
element.appendChild(child);
};
}
I'd be willing to add event handler creation to the utility (using addEventListener). Would that be a feature you'd think fits the project? If so, what kind of syntax should it have?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.