Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add custom element built in support #137

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
350ff77
added custom element support to browser js
AndyOGo Nov 6, 2018
13d2694
updated browserify transform
AndyOGo Nov 6, 2018
18421f5
added babel support
AndyOGo Nov 6, 2018
9cb47b5
added custom element NS support
AndyOGo Nov 6, 2018
9431f91
upgrade browserify transform for NS built in
AndyOGo Nov 6, 2018
57ca34f
added babel upgrade for custom element NS
AndyOGo Nov 6, 2018
ff2e98a
should fix expected spaces after if
AndyOGo Nov 6, 2018
f616617
should fix code style/lint
AndyOGo Nov 6, 2018
ce5b1e0
added babel test
AndyOGo Nov 6, 2018
e76dc7b
refactored babel
AndyOGo Nov 6, 2018
13fe106
should fix babel expected test
AndyOGo Nov 6, 2018
6f7ceb0
added browserify transform test
AndyOGo Nov 6, 2018
80fde2a
added equal spacing to browserify transform
AndyOGo Nov 6, 2018
25f89c1
added stubed test
AndyOGo Nov 6, 2018
edaac74
just log transform result
AndyOGo Nov 6, 2018
312b4f5
fixed code style
AndyOGo Nov 6, 2018
e0bb3c1
detele props.is
AndyOGo Nov 6, 2018
0f9bd60
fixed plan count
AndyOGo Nov 6, 2018
3e4366b
fixed illegal invocation of stub
AndyOGo Nov 6, 2018
586f59a
fixed options stub check
AndyOGo Nov 6, 2018
9817b36
forgat to call t.end
AndyOGo Nov 6, 2018
cdc4895
fixed illegal invocation error
AndyOGo Nov 6, 2018
0572d53
should fix illegal invocation
AndyOGo Nov 6, 2018
8d77ec0
should use delete
AndyOGo Nov 6, 2018
d4757f8
hope that fixed illegal invocation
AndyOGo Nov 6, 2018
597ad14
added Document global
AndyOGo Nov 6, 2018
78728e6
hope that fixes illegal invocation
AndyOGo Nov 6, 2018
0bc5662
just a guess that this code gets transformed
AndyOGo Nov 6, 2018
183c90c
just another try
AndyOGo Nov 6, 2018
da5385e
just added logs
AndyOGo Nov 6, 2018
69dbdad
another try
AndyOGo Nov 6, 2018
5a6478b
fixed illegal invocation of transform code
AndyOGo Nov 6, 2018
8186c6d
fixed lint
AndyOGo Nov 6, 2018
bc07060
added complementary comments
AndyOGo Nov 6, 2018
f0ca21a
hope taht makes standard style happier
AndyOGo Nov 6, 2018
e6b7ee4
fixed misisng soace before function parens
AndyOGo Nov 6, 2018
2f70a76
added complimentary comment
AndyOGo Nov 15, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion lib/babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ module.exports = (babel) => {
const t = babel.types
const nanohtmlModuleNames = ['nanohtml', 'bel', 'yo-yo', 'choo/html']

/**
* Returns an object which specifies the custom elements by which a built-in is extended.
*/
const createExtendsObjectExpression = (is) =>
t.objectExpression([t.objectProperty(t.identifier('is'), t.stringLiteral(is))])

/**
* Returns a node that creates a namespaced HTML element.
*/
Expand All @@ -58,6 +64,15 @@ module.exports = (babel) => {
[ns, t.stringLiteral(tag)]
)

/**
* Returns a node that creates a extended namespaced HTML element.
*/
const createNsCustomBuiltIn = (ns, tag, is) =>
t.callExpression(
t.memberExpression(t.identifier('document'), t.identifier('createElementNS')),
[ns, t.stringLiteral(tag), createExtendsObjectExpression(is)]
)

/**
* Returns a node that creates an element.
*/
Expand All @@ -67,6 +82,15 @@ module.exports = (babel) => {
[t.stringLiteral(tag)]
)

/**
* Returns a node that creates an extended element.
*/
const createCustomBuiltIn = (tag, is) =>
t.callExpression(
t.memberExpression(t.identifier('document'), t.identifier('createElement')),
[t.stringLiteral(tag), createExtendsObjectExpression(is)]
)

/**
* Returns a node that creates a comment.
*/
Expand Down Expand Up @@ -188,10 +212,20 @@ module.exports = (babel) => {

const result = []

var isCustomElement = props.is
delete props.is

// Use the SVG namespace for svg elements.
if (SVG_TAGS.includes(tag)) {
state.svgNamespaceId.used = true
result.push(t.assignmentExpression('=', id, createNsElement(state.svgNamespaceId, tag)))

if (isCustomElement) {
result.push(t.assignmentExpression('=', id, createNsCustomBuiltIn(state.svgNamespaceId, tag, isCustomElement)))
} else {
result.push(t.assignmentExpression('=', id, createNsElement(state.svgNamespaceId, tag)))
}
} else if (isCustomElement) {
result.push(t.assignmentExpression('=', id, createCustomBuiltIn(tag, isCustomElement)))
} else {
result.push(t.assignmentExpression('=', id, createElement(tag)))
}
Expand Down
15 changes: 14 additions & 1 deletion lib/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,24 @@ function nanoHtmlCreateElement (tag, props, children) {
delete props.namespace
}

// If we are extending a builtin element
var isCustomElement = false
if (props.is) {
isCustomElement = props.is
delete props.is
}

// Create the element
if (ns) {
el = document.createElementNS(ns, tag)
if (isCustomElement) {
el = document.createElementNS(ns, tag, { is: isCustomElement })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else {
el = document.createElementNS(ns, tag)
}
} else if (tag === COMMENT_TAG) {
return document.createComment(props.comment)
} else if (isCustomElement) {
el = document.createElement(tag, { is: isCustomElement })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else {
el = document.createElement(tag)
}
Expand Down
12 changes: 11 additions & 1 deletion lib/browserify-transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,19 @@ function processNode (node, args) {
namespace = SVGNS
}

// Whether this element is extended
var isCustomElement = props.is
delete props.is

// Create the element
if (namespace) {
res.push('var ' + elname + ' = document.createElementNS(' + JSON.stringify(namespace) + ', ' + JSON.stringify(tag) + ')')
if (isCustomElement) {
res.push('var ' + elname + ' = document.createElementNS(' + JSON.stringify(namespace) + ', ' + JSON.stringify(tag) + ', { is: ' + JSON.stringify(isCustomElement) + ' })')
} else {
res.push('var ' + elname + ' = document.createElementNS(' + JSON.stringify(namespace) + ', ' + JSON.stringify(tag) + ')')
}
} else if (isCustomElement) {
res.push('var ' + elname + ' = document.createElement(' + JSON.stringify(tag) + ', { is: ' + JSON.stringify(isCustomElement) + ' })')
} else {
res.push('var ' + elname + ' = document.createElement(' + JSON.stringify(tag) + ')')
}
Expand Down
6 changes: 6 additions & 0 deletions tests/babel/fixtures/custom-build-in.expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
var _div,
_appendChild = require('nanohtml/lib/append-child');

_div = document.createElement('div', {
is: 'my-div'
}), _appendChild(_div, ['\n Hello world\n ']), _div;
7 changes: 7 additions & 0 deletions tests/babel/fixtures/custom-build-in.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import html from 'nanohtml'

html`
<div is="my-div">
Hello world
</div>
`
1 change: 1 addition & 0 deletions tests/babel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ function testFixture (name, opts) {
}

testFixture('simple')
testFixture('custom-build-in')
testFixture('empty')
testFixture('this')
testFixture('variableNames')
Expand Down
24 changes: 24 additions & 0 deletions tests/browser/elements.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,27 @@ test('allow objects to be passed', function (t) {
t.ok(result.outerHTML.indexOf('<div foo="bar">hey</div>') !== -1, 'contains foo="bar"')
t.end()
})

test('supports extended build-in elements', function (t) {
t.plan(1)

var originalCreateElement = document.createElement
var optionsArg

// this iife is a must to avoid illegal invocation type errors, caused by transformed nanohtml tests
(function () {
Copy link
Contributor Author

@AndyOGo AndyOGo Nov 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If tape would have before/after or setup/teardown support it could be implemented cleaner, but so far it gets the job done

document.createElement = function () {
optionsArg = arguments[1]
return originalCreateElement.apply(this, arguments)
}
})()

;html`<div is="my-div"></div>`

t.ok(typeof optionsArg === 'object' && optionsArg.is === 'my-div', 'properly passes optional extends object')

// revert to original prototype method
delete document.createElement
goto-bus-stop marked this conversation as resolved.
Show resolved Hide resolved

t.end()
})
5 changes: 3 additions & 2 deletions tests/transform/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ var path = require('path')
var FIXTURE = path.join(__dirname, 'fixture.js')

test('works', function (t) {
t.plan(4)
var src = 'var html = require(\'nanohtml\')\n module.exports = function (data) {\n var className = \'test\'\n return html`<div class="${className}">\n <h1>${data}</h1>\n </div>`\n }' // eslint-disable-line
t.plan(5)
var src = 'var html = require(\'nanohtml\')\n module.exports = function (data) {\n var className = \'test\'\n return html`<div class="${className}">\n <h1>${data}</h1>\n <div is="my-div"></div> </div>`\n }' // eslint-disable-line
fs.writeFileSync(FIXTURE, src)
var b = browserify(FIXTURE, {
browserField: false,
Expand All @@ -19,6 +19,7 @@ test('works', function (t) {
var result = src.toString()
t.ok(result.indexOf('var html = {}') !== -1, 'replaced html dependency with {}')
t.ok(result.indexOf('document.createElement("h1")') !== -1, 'created an h1 tag')
t.ok(result.indexOf('document.createElement("div", { is: "my-div" })') !== -1, 'created an extended build-in element')
t.ok(result.indexOf('setAttribute("class", arguments[1])') !== -1, 'set a class attribute')
t.end()
})
Expand Down