deku 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +5 -0
  6. data/LICENSE +25 -0
  7. data/README.md +28 -0
  8. data/Rakefile +1 -0
  9. data/deku.gemspec +23 -0
  10. data/deps/node_modules/deku.js +2 -0
  11. data/deps/node_modules/deku/.editorconfig +16 -0
  12. data/deps/node_modules/deku/.zuul.yml +15 -0
  13. data/deps/node_modules/deku/History.md +290 -0
  14. data/deps/node_modules/deku/LICENSE.md +7 -0
  15. data/deps/node_modules/deku/Makefile +91 -0
  16. data/deps/node_modules/deku/README.md +293 -0
  17. data/deps/node_modules/deku/index.js +4072 -0
  18. data/deps/node_modules/deku/lib/application.js +85 -0
  19. data/deps/node_modules/deku/lib/index.js +28 -0
  20. data/deps/node_modules/deku/lib/render.js +1300 -0
  21. data/deps/node_modules/deku/lib/stringify.js +105 -0
  22. data/deps/node_modules/deku/lib/svg.js +107 -0
  23. data/deps/node_modules/deku/lib/utils.js +18 -0
  24. data/deps/node_modules/deku/lib/virtual.js +247 -0
  25. data/deps/node_modules/deku/node_modules/array-flatten/LICENSE +21 -0
  26. data/deps/node_modules/deku/node_modules/array-flatten/README.md +43 -0
  27. data/deps/node_modules/deku/node_modules/array-flatten/array-flatten.js +57 -0
  28. data/deps/node_modules/deku/node_modules/array-flatten/package.json +62 -0
  29. data/deps/node_modules/deku/node_modules/component-emitter/History.md +63 -0
  30. data/deps/node_modules/deku/node_modules/component-emitter/LICENSE +24 -0
  31. data/deps/node_modules/deku/node_modules/component-emitter/Readme.md +74 -0
  32. data/deps/node_modules/deku/node_modules/component-emitter/index.js +161 -0
  33. data/deps/node_modules/deku/node_modules/component-emitter/package.json +174 -0
  34. data/deps/node_modules/deku/node_modules/component-raf/.npmignore +2 -0
  35. data/deps/node_modules/deku/node_modules/component-raf/History.md +26 -0
  36. data/deps/node_modules/deku/node_modules/component-raf/Makefile +11 -0
  37. data/deps/node_modules/deku/node_modules/component-raf/Readme.md +46 -0
  38. data/deps/node_modules/deku/node_modules/component-raf/component.json +16 -0
  39. data/deps/node_modules/deku/node_modules/component-raf/example.html +43 -0
  40. data/deps/node_modules/deku/node_modules/component-raf/index.js +34 -0
  41. data/deps/node_modules/deku/node_modules/component-raf/package.json +164 -0
  42. data/deps/node_modules/deku/node_modules/component-type/.npmignore +3 -0
  43. data/deps/node_modules/deku/node_modules/component-type/Makefile +14 -0
  44. data/deps/node_modules/deku/node_modules/component-type/Readme.md +37 -0
  45. data/deps/node_modules/deku/node_modules/component-type/component.json +13 -0
  46. data/deps/node_modules/deku/node_modules/component-type/index.js +34 -0
  47. data/deps/node_modules/deku/node_modules/component-type/package.json +120 -0
  48. data/deps/node_modules/deku/node_modules/component-type/test/index.html +17 -0
  49. data/deps/node_modules/deku/node_modules/component-type/test/mocha.css +231 -0
  50. data/deps/node_modules/deku/node_modules/component-type/test/mocha.js +5340 -0
  51. data/deps/node_modules/deku/node_modules/component-type/test/tests.js +72 -0
  52. data/deps/node_modules/deku/node_modules/dom-pool/.npmignore +1 -0
  53. data/deps/node_modules/deku/node_modules/dom-pool/Pool.js +52 -0
  54. data/deps/node_modules/deku/node_modules/dom-pool/README.md +42 -0
  55. data/deps/node_modules/deku/node_modules/dom-pool/authors.txt +4 -0
  56. data/deps/node_modules/deku/node_modules/dom-pool/bower.json +26 -0
  57. data/deps/node_modules/deku/node_modules/dom-pool/package.json +46 -0
  58. data/deps/node_modules/deku/node_modules/dom-pool/tests.html +16 -0
  59. data/deps/node_modules/deku/node_modules/dom-pool/tests.js +102 -0
  60. data/deps/node_modules/deku/node_modules/dom-walk/.npmignore +3 -0
  61. data/deps/node_modules/deku/node_modules/dom-walk/LICENCE +19 -0
  62. data/deps/node_modules/deku/node_modules/dom-walk/Makefile +2 -0
  63. data/deps/node_modules/deku/node_modules/dom-walk/README.md +23 -0
  64. data/deps/node_modules/deku/node_modules/dom-walk/example/index.js +5 -0
  65. data/deps/node_modules/deku/node_modules/dom-walk/example/static/bundle.js +211 -0
  66. data/deps/node_modules/deku/node_modules/dom-walk/example/static/index.html +16 -0
  67. data/deps/node_modules/deku/node_modules/dom-walk/index.js +24 -0
  68. data/deps/node_modules/deku/node_modules/dom-walk/package.json +57 -0
  69. data/deps/node_modules/deku/node_modules/fast.js/.jshintignore +7 -0
  70. data/deps/node_modules/deku/node_modules/fast.js/.jshintrc +80 -0
  71. data/deps/node_modules/deku/node_modules/fast.js/.npmignore +6 -0
  72. data/deps/node_modules/deku/node_modules/fast.js/.travis.yml +3 -0
  73. data/deps/node_modules/deku/node_modules/fast.js/LICENSE.md +21 -0
  74. data/deps/node_modules/deku/node_modules/fast.js/README.md +552 -0
  75. data/deps/node_modules/deku/node_modules/fast.js/array/clone.js +21 -0
  76. data/deps/node_modules/deku/node_modules/fast.js/array/concat.js +32 -0
  77. data/deps/node_modules/deku/node_modules/fast.js/array/every.js +25 -0
  78. data/deps/node_modules/deku/node_modules/fast.js/array/fill.js +29 -0
  79. data/deps/node_modules/deku/node_modules/fast.js/array/filter.js +26 -0
  80. data/deps/node_modules/deku/node_modules/fast.js/array/forEach.js +21 -0
  81. data/deps/node_modules/deku/node_modules/fast.js/array/index.js +15 -0
  82. data/deps/node_modules/deku/node_modules/fast.js/array/indexOf.js +33 -0
  83. data/deps/node_modules/deku/node_modules/fast.js/array/lastIndexOf.js +29 -0
  84. data/deps/node_modules/deku/node_modules/fast.js/array/map.js +24 -0
  85. data/deps/node_modules/deku/node_modules/fast.js/array/pluck.js +24 -0
  86. data/deps/node_modules/deku/node_modules/fast.js/array/reduce.js +35 -0
  87. data/deps/node_modules/deku/node_modules/fast.js/array/reduceRight.js +35 -0
  88. data/deps/node_modules/deku/node_modules/fast.js/array/some.js +25 -0
  89. data/deps/node_modules/deku/node_modules/fast.js/bower.json +28 -0
  90. data/deps/node_modules/deku/node_modules/fast.js/clone.js +27 -0
  91. data/deps/node_modules/deku/node_modules/fast.js/dist/bench.html +15 -0
  92. data/deps/node_modules/deku/node_modules/fast.js/dist/bench.js +19900 -0
  93. data/deps/node_modules/deku/node_modules/fast.js/dist/fast.js +1450 -0
  94. data/deps/node_modules/deku/node_modules/fast.js/dist/fast.min.js +1 -0
  95. data/deps/node_modules/deku/node_modules/fast.js/filter.js +23 -0
  96. data/deps/node_modules/deku/node_modules/fast.js/forEach.js +22 -0
  97. data/deps/node_modules/deku/node_modules/fast.js/function/apply.js +19 -0
  98. data/deps/node_modules/deku/node_modules/fast.js/function/applyNoContext.js +29 -0
  99. data/deps/node_modules/deku/node_modules/fast.js/function/applyWithContext.js +29 -0
  100. data/deps/node_modules/deku/node_modules/fast.js/function/bind.js +71 -0
  101. data/deps/node_modules/deku/node_modules/fast.js/function/bindInternal3.js +11 -0
  102. data/deps/node_modules/deku/node_modules/fast.js/function/bindInternal4.js +11 -0
  103. data/deps/node_modules/deku/node_modules/fast.js/function/index.js +7 -0
  104. data/deps/node_modules/deku/node_modules/fast.js/function/partial.js +42 -0
  105. data/deps/node_modules/deku/node_modules/fast.js/function/partialConstructor.js +45 -0
  106. data/deps/node_modules/deku/node_modules/fast.js/function/try.js +35 -0
  107. data/deps/node_modules/deku/node_modules/fast.js/index.js +241 -0
  108. data/deps/node_modules/deku/node_modules/fast.js/map.js +23 -0
  109. data/deps/node_modules/deku/node_modules/fast.js/object/assign.js +34 -0
  110. data/deps/node_modules/deku/node_modules/fast.js/object/clone.js +25 -0
  111. data/deps/node_modules/deku/node_modules/fast.js/object/filter.js +28 -0
  112. data/deps/node_modules/deku/node_modules/fast.js/object/forEach.js +23 -0
  113. data/deps/node_modules/deku/node_modules/fast.js/object/index.js +11 -0
  114. data/deps/node_modules/deku/node_modules/fast.js/object/keys.js +17 -0
  115. data/deps/node_modules/deku/node_modules/fast.js/object/map.js +26 -0
  116. data/deps/node_modules/deku/node_modules/fast.js/object/reduce.js +37 -0
  117. data/deps/node_modules/deku/node_modules/fast.js/object/reduceRight.js +37 -0
  118. data/deps/node_modules/deku/node_modules/fast.js/object/values.js +20 -0
  119. data/deps/node_modules/deku/node_modules/fast.js/package.json +73 -0
  120. data/deps/node_modules/deku/node_modules/fast.js/reduce.js +24 -0
  121. data/deps/node_modules/deku/node_modules/fast.js/reduceRight.js +24 -0
  122. data/deps/node_modules/deku/node_modules/fast.js/string/index.js +3 -0
  123. data/deps/node_modules/deku/node_modules/fast.js/string/intern.js +56 -0
  124. data/deps/node_modules/deku/node_modules/get-uid/README.md +44 -0
  125. data/deps/node_modules/deku/node_modules/get-uid/index.js +6 -0
  126. data/deps/node_modules/deku/node_modules/get-uid/package.json +56 -0
  127. data/deps/node_modules/deku/node_modules/is-dom/HISTORY.md +2 -0
  128. data/deps/node_modules/deku/node_modules/is-dom/LICENSE +21 -0
  129. data/deps/node_modules/deku/node_modules/is-dom/README.md +32 -0
  130. data/deps/node_modules/deku/node_modules/is-dom/index.js +15 -0
  131. data/deps/node_modules/deku/node_modules/is-dom/package.json +62 -0
  132. data/deps/node_modules/deku/node_modules/object-path/.npmignore +7 -0
  133. data/deps/node_modules/deku/node_modules/object-path/.travis.yml +6 -0
  134. data/deps/node_modules/deku/node_modules/object-path/LICENSE +21 -0
  135. data/deps/node_modules/deku/node_modules/object-path/README.md +96 -0
  136. data/deps/node_modules/deku/node_modules/object-path/bower.json +17 -0
  137. data/deps/node_modules/deku/node_modules/object-path/component.json +22 -0
  138. data/deps/node_modules/deku/node_modules/object-path/index.js +269 -0
  139. data/deps/node_modules/deku/node_modules/object-path/package.json +89 -0
  140. data/deps/node_modules/deku/node_modules/object-path/test.js +510 -0
  141. data/deps/node_modules/deku/node_modules/per-frame/.npmignore +68 -0
  142. data/deps/node_modules/deku/node_modules/per-frame/History.md +32 -0
  143. data/deps/node_modules/deku/node_modules/per-frame/README.md +44 -0
  144. data/deps/node_modules/deku/node_modules/per-frame/component.json +13 -0
  145. data/deps/node_modules/deku/node_modules/per-frame/index.js +37 -0
  146. data/deps/node_modules/deku/node_modules/per-frame/package.json +143 -0
  147. data/deps/node_modules/deku/node_modules/per-frame/test/test.js +94 -0
  148. data/deps/node_modules/deku/node_modules/sliced/.npmignore +2 -0
  149. data/deps/node_modules/deku/node_modules/sliced/.travis.yml +4 -0
  150. data/deps/node_modules/deku/node_modules/sliced/History.md +30 -0
  151. data/deps/node_modules/deku/node_modules/sliced/LICENSE +22 -0
  152. data/deps/node_modules/deku/node_modules/sliced/Makefile +5 -0
  153. data/deps/node_modules/deku/node_modules/sliced/README.md +62 -0
  154. data/deps/node_modules/deku/node_modules/sliced/bench.js +95 -0
  155. data/deps/node_modules/deku/node_modules/sliced/component.json +14 -0
  156. data/deps/node_modules/deku/node_modules/sliced/index.js +1 -0
  157. data/deps/node_modules/deku/node_modules/sliced/lib/sliced.js +33 -0
  158. data/deps/node_modules/deku/node_modules/sliced/package.json +52 -0
  159. data/deps/node_modules/deku/node_modules/sliced/test/index.js +80 -0
  160. data/deps/node_modules/deku/package.json +67 -0
  161. data/lib/deku.rb +11 -0
  162. data/lib/deku/application.rb +16 -0
  163. data/lib/deku/component.rb +36 -0
  164. data/lib/deku/context.rb +38 -0
  165. data/lib/deku/element_node.rb +17 -0
  166. data/lib/deku/version.rb +4 -0
  167. metadata +278 -0
@@ -0,0 +1,105 @@
1
+ var utils = require('./utils')
2
+ var defaults = utils.defaults
3
+
4
+ /**
5
+ * Expose `stringify`.
6
+ */
7
+
8
+ module.exports = function (app) {
9
+ if (!app.element) {
10
+ throw new Error('No element mounted')
11
+ }
12
+
13
+ /**
14
+ * Render to string.
15
+ *
16
+ * @param {Component} component
17
+ * @param {Object} [props]
18
+ * @return {String}
19
+ */
20
+
21
+ function stringify (component, optProps) {
22
+ var propTypes = component.propTypes || {}
23
+ var state = component.initialState ? component.initialState() : {}
24
+ var props = defaults(optProps, component.defaultProps || {})
25
+
26
+ for (var name in propTypes) {
27
+ var options = propTypes[name]
28
+ if (options.source) {
29
+ props[name] = app.sources[options.source]
30
+ }
31
+ }
32
+
33
+ if (component.beforeMount) component.beforeMount({ props: props, state: state })
34
+ if (component.beforeRender) component.beforeRender({ props: props, state: state })
35
+ var node = component.render({ props: props, state: state })
36
+ return stringifyNode(node, '0')
37
+ }
38
+
39
+ /**
40
+ * Render a node to a string
41
+ *
42
+ * @param {Node} node
43
+ * @param {Tree} tree
44
+ *
45
+ * @return {String}
46
+ */
47
+
48
+ function stringifyNode (node, path) {
49
+ switch (node.type) {
50
+ case 'text': return node.data
51
+ case 'element':
52
+ var children = node.children
53
+ var attributes = node.attributes
54
+ var tagName = node.tagName
55
+ var innerHTML = attributes.innerHTML
56
+ var str = '<' + tagName + attrs(attributes) + '>'
57
+
58
+ if (innerHTML) {
59
+ str += innerHTML
60
+ } else {
61
+ for (var i = 0, n = children.length; i < n; i++) {
62
+ str += stringifyNode(children[i], path + '.' + i)
63
+ }
64
+ }
65
+
66
+ str += '</' + tagName + '>'
67
+ return str
68
+ case 'component': return stringify(node.component, node.props)
69
+ }
70
+
71
+ throw new Error('Invalid type')
72
+ }
73
+
74
+ return stringifyNode(app.element, '0')
75
+ }
76
+
77
+ /**
78
+ * HTML attributes to string.
79
+ *
80
+ * @param {Object} attributes
81
+ * @return {String}
82
+ * @api private
83
+ */
84
+
85
+ function attrs (attributes) {
86
+ var str = ''
87
+ for (var key in attributes) {
88
+ if (key === 'innerHTML') continue
89
+ str += attr(key, attributes[key])
90
+ }
91
+ return str
92
+ }
93
+
94
+ /**
95
+ * HTML attribute to string.
96
+ *
97
+ * @param {String} key
98
+ * @param {String} val
99
+ * @return {String}
100
+ * @api private
101
+ */
102
+
103
+ function attr (key, val) {
104
+ return ' ' + key + '="' + val + '"'
105
+ }
@@ -0,0 +1,107 @@
1
+ var fast = require('fast.js')
2
+ var indexOf = fast.indexOf
3
+
4
+ /**
5
+ * This file lists the supported SVG elements used by the
6
+ * renderer. We may add better SVG support in the future
7
+ * that doesn't require whitelisting elements.
8
+ */
9
+
10
+ exports.namespace = 'http://www.w3.org/2000/svg'
11
+
12
+ /**
13
+ * Supported SVG elements
14
+ *
15
+ * @type {Array}
16
+ */
17
+
18
+ exports.elements = [
19
+ 'circle',
20
+ 'defs',
21
+ 'ellipse',
22
+ 'g',
23
+ 'line',
24
+ 'linearGradient',
25
+ 'mask',
26
+ 'path',
27
+ 'pattern',
28
+ 'polygon',
29
+ 'polyline',
30
+ 'radialGradient',
31
+ 'rect',
32
+ 'stop',
33
+ 'svg',
34
+ 'text',
35
+ 'tspan'
36
+ ]
37
+
38
+ /**
39
+ * Supported SVG attributes
40
+ */
41
+
42
+ exports.attributes = [
43
+ 'cx',
44
+ 'cy',
45
+ 'd',
46
+ 'dx',
47
+ 'dy',
48
+ 'fill',
49
+ 'fillOpacity',
50
+ 'fontFamily',
51
+ 'fontSize',
52
+ 'fx',
53
+ 'fy',
54
+ 'gradientTransform',
55
+ 'gradientUnits',
56
+ 'markerEnd',
57
+ 'markerMid',
58
+ 'markerStart',
59
+ 'offset',
60
+ 'opacity',
61
+ 'patternContentUnits',
62
+ 'patternUnits',
63
+ 'points',
64
+ 'preserveAspectRatio',
65
+ 'r',
66
+ 'rx',
67
+ 'ry',
68
+ 'spreadMethod',
69
+ 'stopColor',
70
+ 'stopOpacity',
71
+ 'stroke',
72
+ 'strokeDasharray',
73
+ 'strokeLinecap',
74
+ 'strokeOpacity',
75
+ 'strokeWidth',
76
+ 'textAnchor',
77
+ 'transform',
78
+ 'version',
79
+ 'viewBox',
80
+ 'x1',
81
+ 'x2',
82
+ 'x',
83
+ 'y1',
84
+ 'y2',
85
+ 'y'
86
+ ]
87
+
88
+ /**
89
+ * Is element's namespace SVG?
90
+ *
91
+ * @param {String} name
92
+ */
93
+
94
+ exports.isElement = function (name) {
95
+ return indexOf(exports.elements, name) !== -1
96
+ }
97
+
98
+ /**
99
+ * Are element's attributes SVG?
100
+ *
101
+ * @param {String} attr
102
+ */
103
+
104
+ exports.isAttribute = function (attr) {
105
+ return indexOf(exports.attributes, attr) !== -1
106
+ }
107
+
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The npm 'defaults' module but without clone because
3
+ * it was requiring the 'Buffer' module which is huge.
4
+ *
5
+ * @param {Object} options
6
+ * @param {Object} defaults
7
+ *
8
+ * @return {Object}
9
+ */
10
+
11
+ exports.defaults = function(options, defaults) {
12
+ Object.keys(defaults).forEach(function(key) {
13
+ if (typeof options[key] === 'undefined') {
14
+ options[key] = defaults[key]
15
+ }
16
+ })
17
+ return options
18
+ }
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Module dependencies.
3
+ */
4
+
5
+ var type = require('component-type')
6
+ var slice = require('sliced')
7
+ var flatten = require('array-flatten')
8
+
9
+ /**
10
+ * This function lets us create virtual nodes using a simple
11
+ * syntax. It is compatible with JSX transforms so you can use
12
+ * JSX to write nodes that will compile to this function.
13
+ *
14
+ * let node = virtual('div', { id: 'foo' }, [
15
+ * virtual('a', { href: 'http://google.com' }, 'Google')
16
+ * ])
17
+ *
18
+ * You can leave out the attributes or the children if either
19
+ * of them aren't needed and it will figure out what you're
20
+ * trying to do.
21
+ */
22
+
23
+ module.exports = virtual
24
+
25
+ /**
26
+ * Create virtual DOM trees.
27
+ *
28
+ * This creates the nicer API for the user.
29
+ * It translates that friendly API into an actual tree of nodes.
30
+ *
31
+ * @param {String|Function} type
32
+ * @param {Object} props
33
+ * @param {Array} children
34
+ * @return {Node}
35
+ * @api public
36
+ */
37
+
38
+ function virtual (type, props, children) {
39
+ // Default to div with no args
40
+ if (!type) {
41
+ throw new Error('Element needs a type. https://gist.github.com/anthonyshort/77ced43b5defe39908af')
42
+ }
43
+
44
+ // Skipped adding attributes and we're passing
45
+ // in children instead.
46
+ if (arguments.length === 2 && (typeof props === 'string' || Array.isArray(props))) {
47
+ children = props
48
+ props = {}
49
+ }
50
+
51
+ // Account for JSX putting the children as multiple arguments.
52
+ // This is essentially just the ES6 rest param
53
+ if (arguments.length > 2 && Array.isArray(arguments[2]) === false) {
54
+ children = slice(arguments, 2)
55
+ }
56
+
57
+ children = children || []
58
+ props = props || {}
59
+
60
+ // passing in a single child, you can skip
61
+ // using the array
62
+ if (!Array.isArray(children)) {
63
+ children = [ children ]
64
+ }
65
+
66
+ children = flatten(children, 1).reduce(normalize, [])
67
+
68
+ // pull the key out from the data.
69
+ var key = 'key' in props ? String(props.key) : null
70
+ delete props['key']
71
+
72
+ // if you pass in a function, it's a `Component` constructor.
73
+ // otherwise it's an element.
74
+ var node
75
+ if (typeof type === 'string') {
76
+ node = new ElementNode(type, props, key, children)
77
+ } else {
78
+ node = new ComponentNode(type, props, key, children)
79
+ }
80
+
81
+ // set the unique ID
82
+ node.index = 0
83
+
84
+ return node
85
+ }
86
+
87
+ /**
88
+ * Parse nodes into real `Node` objects.
89
+ *
90
+ * @param {Mixed} node
91
+ * @param {Integer} index
92
+ * @return {Node}
93
+ * @api private
94
+ */
95
+
96
+ function normalize (acc, node) {
97
+ if (node == null) {
98
+ return acc
99
+ }
100
+ if (typeof node === 'string' || typeof node === 'number') {
101
+ var newNode = new TextNode(String(node))
102
+ newNode.index = acc.length
103
+ acc.push(newNode)
104
+ } else {
105
+ node.index = acc.length
106
+ acc.push(node)
107
+ }
108
+ return acc
109
+ }
110
+
111
+ /**
112
+ * Initialize a new `ComponentNode`.
113
+ *
114
+ * @param {Component} component
115
+ * @param {Object} props
116
+ * @param {String} key Used for sorting/replacing during diffing.
117
+ * @param {Array} children Child virtual nodes
118
+ * @api public
119
+ */
120
+
121
+ function ComponentNode (component, props, key, children) {
122
+ this.key = key
123
+ this.props = props
124
+ this.type = 'component'
125
+ this.component = component
126
+ this.props.children = children || []
127
+ }
128
+
129
+ /**
130
+ * Initialize a new `ElementNode`.
131
+ *
132
+ * @param {String} tagName
133
+ * @param {Object} attributes
134
+ * @param {String} key Used for sorting/replacing during diffing.
135
+ * @param {Array} children Child virtual dom nodes.
136
+ * @api public
137
+ */
138
+
139
+ function ElementNode (tagName, attributes, key, children) {
140
+ this.type = 'element'
141
+ this.attributes = parseAttributes(attributes)
142
+ this.tagName = tagName
143
+ this.children = children || []
144
+ this.key = key
145
+ }
146
+
147
+ /**
148
+ * Initialize a new `TextNode`.
149
+ *
150
+ * This is just a virtual HTML text object.
151
+ *
152
+ * @param {String} text
153
+ * @api public
154
+ */
155
+
156
+ function TextNode (text) {
157
+ this.type = 'text'
158
+ this.data = String(text)
159
+ }
160
+
161
+ /**
162
+ * Parse attributes for some special cases.
163
+ *
164
+ * TODO: This could be more functional and allow hooks
165
+ * into the processing of the attributes at a component-level
166
+ *
167
+ * @param {Object} attributes
168
+ *
169
+ * @return {Object}
170
+ */
171
+
172
+ function parseAttributes (attributes) {
173
+ // style: { 'text-align': 'left' }
174
+ if (attributes.style) {
175
+ attributes.style = parseStyle(attributes.style)
176
+ }
177
+
178
+ // class: { foo: true, bar: false, baz: true }
179
+ // class: ['foo', 'bar', 'baz']
180
+ if (attributes.class) {
181
+ attributes.class = parseClass(attributes.class)
182
+ }
183
+
184
+ // Remove attributes with false values
185
+ var filteredAttributes = {}
186
+ for (var key in attributes) {
187
+ var value = attributes[key]
188
+ if (value == null || value === false) continue
189
+ filteredAttributes[key] = value
190
+ }
191
+
192
+ return filteredAttributes
193
+ }
194
+
195
+ /**
196
+ * Parse a block of styles into a string.
197
+ *
198
+ * TODO: this could do a lot more with vendor prefixing,
199
+ * number values etc. Maybe there's a way to allow users
200
+ * to hook into this?
201
+ *
202
+ * @param {Object} styles
203
+ *
204
+ * @return {String}
205
+ */
206
+
207
+ function parseStyle (styles) {
208
+ if (type(styles) === 'string') {
209
+ return styles
210
+ }
211
+ var str = ''
212
+ for (var name in styles) {
213
+ var value = styles[name]
214
+ str = str + name + ':' + value + ';'
215
+ }
216
+ return str;
217
+ }
218
+
219
+ /**
220
+ * Parse the class attribute so it's able to be
221
+ * set in a more user-friendly way
222
+ *
223
+ * @param {String|Object|Array} value
224
+ *
225
+ * @return {String}
226
+ */
227
+
228
+ function parseClass (value) {
229
+ // { foo: true, bar: false, baz: true }
230
+ if (type(value) === 'object') {
231
+ var matched = []
232
+ for (var key in value) {
233
+ if (value[key]) matched.push(key)
234
+ }
235
+ value = matched
236
+ }
237
+
238
+ // ['foo', 'bar', 'baz']
239
+ if (type(value) === 'array') {
240
+ if (value.length === 0) {
241
+ return
242
+ }
243
+ value = value.join(' ')
244
+ }
245
+
246
+ return value
247
+ }