@litejs/dom 23.4.0 → 23.7.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 (2) hide show
  1. package/index.js +100 -69
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -6,6 +6,8 @@
6
6
  var boolAttrs = {
7
7
  async:1, autoplay:1, loop:1, checked:1, defer:1, disabled:1, muted:1, multiple:1, nomodule:1, playsinline:1, readonly:1, required:1, selected:1
8
8
  }
9
+ , numAttrs = "height maxLength minLength size tabIndex width"
10
+ , strAttrs = "accept accesskey autocapitalize autofocus capture class contenteditable crossorigin dir for hidden href id integrity lang name nonce slot spellcheck src title type translate"
9
11
  , defaultAttrs = {
10
12
  "form method get":1, "input type text":1,
11
13
  "script type text/javascript":1, "style type text/css":1
@@ -81,7 +83,7 @@ var boolAttrs = {
81
83
  }
82
84
  tree.appendChild(child)
83
85
  if ((re = rawTextElements[child.tagName])) {
84
- for (text = ""; (m = tagRe.exec(html)) && !re.test(m[0]); text += m[3] || m[2] || m[0]);
86
+ for (text = ""; (m = tagRe.exec(html)) && !re.test(m[0]); text += m[3] || m[0]);
85
87
  child.textContent = text.replace(unescRe, unescFn)
86
88
  } else if (!voidElements[child.tagName] && !m[8]) tree = child
87
89
  } else {
@@ -109,23 +111,11 @@ var boolAttrs = {
109
111
  this.parentNode.replaceChild(frag, this)
110
112
  return html
111
113
  },
112
- get htmlFor() {
113
- return this["for"]
114
- },
115
- set htmlFor(value) {
116
- this["for"] = value
117
- },
118
- get className() {
119
- return this["class"] || ""
120
- },
121
- set className(value) {
122
- this["class"] = value
123
- },
124
114
  get style() {
125
- return this.styleMap || (this.styleMap = new StyleMap())
115
+ return this._style || (this._style = new CSSStyleDeclaration(this.getAttribute("style") || ""))
126
116
  },
127
117
  set style(value) {
128
- this.styleMap = new StyleMap(value)
118
+ this.setAttribute("style", value)
129
119
  },
130
120
  contains: function (el) {
131
121
  for (; el; el = el.parentNode) if (el === this) return true
@@ -134,6 +124,9 @@ var boolAttrs = {
134
124
  hasChildNodes: function() {
135
125
  return this.childNodes && this.childNodes.length > 0
136
126
  },
127
+ getElementById: function(id) {
128
+ return selector.find(this, "#" + id, 1)
129
+ },
137
130
  appendChild: function(el) {
138
131
  return this.insertBefore(el)
139
132
  },
@@ -186,6 +179,12 @@ var boolAttrs = {
186
179
  }
187
180
  return clone
188
181
  },
182
+ querySelector: function(sel) {
183
+ return selector.find(this, sel, 1)
184
+ },
185
+ querySelectorAll: function(sel) {
186
+ return selector.find(this, sel)
187
+ },
189
188
  toString: function(minify) {
190
189
  return rawTextElements[this.tagName] ? this.textContent : this.hasChildNodes() ? this.childNodes.reduce(function(memo, node) {
191
190
  return memo + node.toString(minify)
@@ -207,33 +206,23 @@ var boolAttrs = {
207
206
  },
208
207
  replaceChildren: replaceChildren,
209
208
  hasAttribute: function(name) {
210
- name = escAttr(name)
211
- return hasOwn.call(this, name === "style" ? "styleMap" : name)
209
+ return this.attributes.getNamedItem(name) != null
212
210
  },
213
211
  getAttribute: function(name) {
214
- return this.hasAttribute(name) ? "" + this[escAttr(name)] : null
212
+ var attr = this.attributes.getNamedItem(name)
213
+ return attr ? attr.value : null
215
214
  },
216
215
  setAttribute: function(name, value) {
217
- this[escAttr(name)] = "" + value
216
+ this.attributes.setNamedItem(name, value)
218
217
  },
219
218
  removeAttribute: function(name) {
220
- name = escAttr(name)
221
- delete this[name === "style" ? "styleMap" : name]
222
- },
223
- getElementById: function(id) {
224
- return selector.find(this, "#" + id, 1)
219
+ this.attributes.removeNamedItem(name)
225
220
  },
226
221
  getElementsByTagName: function(tag) {
227
222
  return selector.find(this, tag)
228
223
  },
229
224
  getElementsByClassName: function(sel) {
230
225
  return selector.find(this, "." + sel.replace(/\s+/g, "."))
231
- },
232
- querySelector: function(sel) {
233
- return selector.find(this, sel, 1)
234
- },
235
- querySelectorAll: function(sel) {
236
- return selector.find(this, sel)
237
226
  }
238
227
  }
239
228
  , quotedAttrRe = /[\s"'`=<>]/
@@ -246,6 +235,26 @@ var boolAttrs = {
246
235
  "&sect;": "§", "&sup2;": "²", "&sup3;": "³", "&yen;": "¥"
247
236
  }
248
237
 
238
+ Object.keys(boolAttrs).forEach(addGetter, { isBool: true })
239
+ numAttrs.split(" ").forEach(addGetter, { isNum: true })
240
+ strAttrs.split(" ").forEach(addGetter, { })
241
+
242
+ function addGetter(key) {
243
+ var attr = key.toLowerCase()
244
+ Object.defineProperty(Element, key == "for" ? "htmlFor" : key == "class" ? "className" : key, {
245
+ configurable: true,
246
+ enumerable: true,
247
+ get: (
248
+ this.isBool ? function() { return this.hasAttribute(attr) } :
249
+ this.isNum ? function() { return +this.getAttribute(attr) || 0 } :
250
+ function() { return this.getAttribute(attr) || "" }
251
+ ),
252
+ set: function(value) {
253
+ this.setAttribute(attr, value)
254
+ }
255
+ })
256
+ }
257
+
249
258
  function escFn(chr) {
250
259
  return chr === "<" ? "&lt;" : "&amp;"
251
260
  }
@@ -260,35 +269,73 @@ function unescFn(ent, hex, num) {
260
269
  }
261
270
  })
262
271
 
263
- function Attr(node, name) {
272
+ function Attr(node, name, value) {
264
273
  this.ownerElement = node
265
274
  this.name = name.toLowerCase()
275
+ this.value = "" + value
276
+ }
277
+
278
+ function NamedNodeMap(node) {
279
+ Object.defineProperty(this, "length", { get: function() { return this.names().length } })
280
+ Object.defineProperty(this, "ownerElement", { value: node })
266
281
  }
267
282
 
268
- Attr.prototype = {
269
- get value() { return this.ownerElement.getAttribute(this.name) },
270
- set value(val) { this.ownerElement.setAttribute(this.name, val) },
283
+ NamedNodeMap.prototype = {
284
+ names: function() {
285
+ this.getNamedItem("style")
286
+ return Object.keys(this)
287
+ },
288
+ getNamedItem: function(name) {
289
+ var loName = name.toLowerCase()
290
+ , attr = this[loName] || null
291
+ if (loName === "style" && this.ownerElement._style) {
292
+ if (attr === null) attr = this[loName] = new Attr(this.ownerElement, name, "")
293
+ attr.value = this.ownerElement._style.valueOf()
294
+ delete this.ownerElement._style
295
+ }
296
+ return attr
297
+ },
298
+ removeNamedItem: function(name) {
299
+ var loName = name.toLowerCase()
300
+ , attr = this[loName] || null
301
+ if (loName === "style") delete this.ownerElement._style
302
+ if (attr !== null) delete this[loName]
303
+ return attr
304
+ },
305
+ setNamedItem: function(name, value) {
306
+ this.removeNamedItem(name)
307
+ var loName = name.toLowerCase()
308
+ if (loName === "style") value = new CSSStyleDeclaration(value).valueOf()
309
+ this[loName] = new Attr(this.ownerElement, name, value)
310
+ },
271
311
  toString: function(minify) {
272
- var value = this.value.replace(escRe, escFn)
273
- if (this.ownerElement.ownerDocument.contentType !== "application/xml") {
274
- if (hasOwn.call(boolAttrs, this.name)) return this.name
275
- if (minify) {
276
- if (hasOwn.call(defaultAttrs, (this.ownerElement.tagName + " " + this.name + " " + value).toLowerCase())) return
277
- if (!quotedAttrRe.test(value)) return this.name + "=" + this.value
278
- if (value.split("\"").length > value.split("'").length) return this.name + "='" + value.replace(/'/g, "&#39;") + "'"
312
+ var map = this
313
+ , tagName = map.ownerElement.tagName
314
+ , isXml = map.ownerElement.ownerDocument.contentType === "application/xml"
315
+ return map.names().map(function(loName) {
316
+ var attr = map.getNamedItem(loName)
317
+ , name = attr.name
318
+ , value = attr.value.replace(escRe, escFn)
319
+ if (!isXml) {
320
+ if (hasOwn.call(boolAttrs, loName)) return name
321
+ if (minify) {
322
+ if (hasOwn.call(defaultAttrs, (tagName + " " + name + " " + value).toLowerCase())) return
323
+ if (!quotedAttrRe.test(value)) return name + "=" + value
324
+ if (value.split("\"").length > value.split("'").length) return name + "='" + value.replace(/'/g, "&#39;") + "'"
325
+ }
279
326
  }
280
- }
281
- return this.name + "=\"" + value.replace(/"/g, "&quot;") + "\""
327
+ return name + "=\"" + value.replace(/"/g, "&quot;") + "\""
328
+ }).filter(Boolean).join(" ")
282
329
  }
283
330
  }
284
331
 
285
- function StyleMap(style) {
332
+ function CSSStyleDeclaration(style) {
286
333
  for (var m, re = /(?:^|;)\s*([-a-z]+)\s*:((?:("|')(?:\\.|(?!\3)[^\\])*?\3|[^"';])+)(?=;|$)/ig; (m = re.exec(style)); ) {
287
334
  this[m[1] === "float" ? "cssFloat" : camelCase(m[1])] = m[2].trim()
288
335
  }
289
336
  }
290
337
 
291
- StyleMap.prototype.valueOf = function() {
338
+ CSSStyleDeclaration.prototype.valueOf = function() {
292
339
  return Object.keys(this).map(function(key) {
293
340
  return (key === "cssFloat" ? "float:" : hyphenCase(key) + ":") + this[key]
294
341
  }, this).join(";")
@@ -298,28 +345,21 @@ function DocumentFragment() {
298
345
  this.childNodes = []
299
346
  }
300
347
 
301
- extendNode(DocumentFragment, Element, {
348
+ extendNode(DocumentFragment, Node, {
302
349
  nodeType: 11,
303
350
  nodeName: "#document-fragment"
304
351
  })
305
352
 
306
353
  function HTMLElement(tag) {
307
354
  var el = this
308
- el.nodeName = el.tagName = tag.toUpperCase()
309
- el.localName = tag.toLowerCase()
355
+ el.attributes = new NamedNodeMap(el)
310
356
  el.childNodes = []
357
+ el.localName = tag.toLowerCase()
358
+ el.nodeName = el.tagName = tag.toUpperCase()
311
359
  }
312
360
 
313
361
  extendNode(HTMLElement, Element, {
314
362
  nodeType: 1,
315
- get attributes() {
316
- var key
317
- , attrs = []
318
- , el = this
319
- for (key in el) if (key === escAttr(key) && el.hasAttribute(key))
320
- attrs.push(new Attr(el, escAttr(key)))
321
- return attrs
322
- },
323
363
  matches: function(sel) {
324
364
  return selector.matches(this, sel)
325
365
  },
@@ -329,9 +369,8 @@ extendNode(HTMLElement, Element, {
329
369
  namespaceURI: "http://www.w3.org/1999/xhtml",
330
370
  localName: null,
331
371
  tagName: null,
332
- styleMap: null,
333
372
  toString: function(minify) {
334
- var attrs = (minify ? this.attributes.map(toMinString).filter(Boolean) : this.attributes).join(" ")
373
+ var attrs = this.attributes.toString(minify)
335
374
  return "<" + this.localName + (attrs ? " " + attrs + (attrs.slice(-1) === "/" ? " >" : ">") : ">") +
336
375
  (voidElements[this.tagName] ? "" : Node.toString.call(this, minify) + "</" + this.localName + ">")
337
376
  }
@@ -339,9 +378,10 @@ extendNode(HTMLElement, Element, {
339
378
 
340
379
  function ElementNS(namespace, tag) {
341
380
  var el = this
381
+ el.attributes = new NamedNodeMap(el)
382
+ el.childNodes = []
342
383
  el.namespaceURI = namespace
343
384
  el.nodeName = el.tagName = el.localName = tag
344
- el.childNodes = []
345
385
  }
346
386
 
347
387
  ElementNS.prototype = HTMLElement.prototype
@@ -456,11 +496,6 @@ function getSibling(node, step, type) {
456
496
  return type > 0 ? getElement(silbings, index + step, step, type) : silbings[index + step] || null
457
497
  }
458
498
 
459
- function escAttr(name) {
460
- name = name.toLowerCase()
461
- return name === "constructor" || name === "attributes" ? name.toUpperCase() : name
462
- }
463
-
464
499
  function camelCase(str) {
465
500
  return str.replace(/-([a-z])/g, function(_, a) { return a.toUpperCase() })
466
501
  }
@@ -469,14 +504,10 @@ function hyphenCase(str) {
469
504
  return str.replace(/[A-Z]/g, "-$&").toLowerCase()
470
505
  }
471
506
 
472
- function toMinString(item) {
473
- return item.toString(true)
474
- }
475
-
476
507
  exports.document = new Document()
477
508
  exports.DOMParser = DOMParser
478
509
  exports.XMLSerializer = XMLSerializer
479
- exports.StyleMap = StyleMap
510
+ exports.CSSStyleDeclaration = CSSStyleDeclaration
480
511
  exports.Node = Node
481
512
  exports.HTMLElement = HTMLElement
482
513
  exports.DocumentFragment = DocumentFragment
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litejs/dom",
3
- "version": "23.4.0",
3
+ "version": "23.7.0",
4
4
  "description": "A small DOM library for server-side testing, rendering, and handling of HTML files",
5
5
  "license": "MIT",
6
6
  "author": "Lauri Rooden <lauri@rooden.ee>",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "repository": "github:litejs/dom",
23
23
  "devDependencies": {
24
- "@litejs/cli": "23.4.3",
24
+ "@litejs/cli": "23.7.0",
25
25
  "jshint": "2.13.6"
26
26
  },
27
27
  "litejs": {