domql 1.5.17 → 1.5.19

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.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "DOM rendering Javascript framework at early stage.",
4
4
  "private": false,
5
5
  "author": "rackai",
6
- "version": "1.5.17",
6
+ "version": "1.5.19",
7
7
  "repository": "https://github.com/rackai/domql",
8
8
  "publishConfig": {
9
9
  "registry": "https://registry.npmjs.org"
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  import DOM from '../../src'
4
- import { isObjectLike, exec, isObject, isEqualDeep } from '../../src/utils'
4
+ import { isObjectLike, exec, isObject, isEqualDeep, memoize } from '../../src/utils'
5
5
  import { classList } from '../../src/element/mixins'
6
6
  import createEmotion from '@emotion/css/create-instance'
7
7
  const ENV = process.env.NODE_ENV
@@ -26,23 +26,32 @@ export const initEmotion = (container, options) => {
26
26
  if (isObjectLike(element.class)) element.class.elementStyle = execPareams
27
27
  else element.class = { elementStyle: execPareams }
28
28
  }
29
- classf(element.class, element, node)
29
+ classf(element.class, element, node, true)
30
30
  }
31
31
 
32
- const classf = (params, element, node) => {
33
- const { __class } = element
34
- if (isObjectLike(params)) {
35
- const classObjHelper = {}
36
- for (const key in params) {
37
- const prop = exec(params[key], element)
38
- if (!prop && prop === __class[key]) continue
39
- __class[key] = prop
32
+ const classf = (params, element, node, flag) => {
33
+ if (element.style && !flag) return
34
+ const { __class, __classNames } = element
35
+ if (!isObjectLike(params)) return
36
+
37
+ for (const key in params) {
38
+ const prop = exec(params[key], element)
39
+
40
+ if (!prop) {
41
+ delete __class[key]
42
+ delete __classNames[key] = CSSed
43
+ continue
44
+ }
45
+
46
+ const isEqual = isEqualDeep(__class[key], prop)
47
+ if (!isEqual) {
40
48
  if ((ENV === 'test' || ENV === 'development') && isObject(prop)) prop.label = key || element.key
41
49
  const CSSed = css(prop)
42
- classObjHelper[key] = CSSed
50
+ __class[key] = prop
51
+ __classNames[key] = CSSed
43
52
  }
44
- classList(classObjHelper, element, node)
45
53
  }
54
+ classList(__classNames, element, node)
46
55
  }
47
56
 
48
57
  DOM.define({
@@ -12,7 +12,7 @@ import update from './update'
12
12
  import * as on from '../event/on'
13
13
  import { assignClass } from './mixins/classList'
14
14
  import { isFunction, isNumber, isString, createID, isNode, exec } from '../utils'
15
- import { remove, lookup, setProps, log, keys, parse, parseDeep } from './methods'
15
+ import { remove, lookup, setProps, log, keys, parse, parseDeep, spotByPath } from './methods'
16
16
  import cacheNode from './cache'
17
17
  import { registry } from './mixins'
18
18
  // import { overwrite, clone, fillTheRest } from '../utils'
@@ -24,7 +24,11 @@ const ENV = process.env.NODE_ENV
24
24
  */
25
25
  const create = (element, parent, key, options = {}) => {
26
26
  // if ELEMENT is not given
27
- if (element === undefined) element = {}
27
+ if (element === undefined) {
28
+ if (ENV === 'test' || ENV === 'development')
29
+ console.warn(key, 'element is undefined in', parent && parent.path)
30
+ element = {}
31
+ }
28
32
  if (element === null) return
29
33
 
30
34
  // if element is extend
@@ -83,21 +87,34 @@ const create = (element, parent, key, options = {}) => {
83
87
  if (options.ignoreChildExtend) delete options.ignoreChildExtend
84
88
  }
85
89
 
86
- // enable STATE
87
- element.state = createState(element, parent)
88
-
89
90
  // create and assign a KEY
90
91
  element.key = assignedKey
91
92
 
92
- // don't render IF in condition
93
- if (isFunction(element.if)) {
94
- // TODO: move as fragment
95
- if (!element.if(element, element.state)) {
96
- const ifFragment = cacheNode({ tag: 'fragment' })
97
- element.__ifFragment = appendNode(ifFragment, parent.node)
98
- element.__ifFalsy = true
99
- }
100
- }
93
+ // enable TRANSFORM in data
94
+ if (!element.transform) element.transform = {}
95
+
96
+ // enable CACHING
97
+ if (!element.__cached) element.__cached = {}
98
+
99
+ // enable EXEC
100
+ if (!element.__exec) element.__exec = {}
101
+
102
+ // enable CLASS CACHING
103
+ if (!element.__class) element.__class = {}
104
+ if (!element.__classNames) element.__classNames = {}
105
+
106
+ // enable CLASS CACHING
107
+ if (!element.__attr) element.__attr = {}
108
+
109
+ // enable CHANGES storing
110
+ if (!element.__changes) element.__changes = []
111
+
112
+ // enable CHANGES storing
113
+ if (!element.__children) element.__children = []
114
+
115
+ // Add _root element property
116
+ const hasRoot = parent.parent && parent.parent.key === ':root'
117
+ if (!element.__root) element.__root = hasRoot ? parent : parent.__root
101
118
 
102
119
  // set the PATH array
103
120
  if (ENV === 'test' || ENV === 'development') {
@@ -105,11 +122,6 @@ const create = (element, parent, key, options = {}) => {
105
122
  element.path = parent.path.concat(assignedKey)
106
123
  }
107
124
 
108
- // if it already HAS a NODE
109
- if (element.node && !element.__ifFalsy) { // TODO: check on if
110
- return assignNode(element, parent, assignedKey)
111
- }
112
-
113
125
  // assign METHODS
114
126
  element.set = set
115
127
  element.update = update
@@ -117,6 +129,7 @@ const create = (element, parent, key, options = {}) => {
117
129
  element.removeContent = removeContentElement
118
130
  element.setProps = setProps
119
131
  element.lookup = lookup
132
+ element.spotByPath = spotByPath
120
133
  element.parse = parse
121
134
  element.parseDeep = parseDeep
122
135
  element.keys = keys
@@ -124,29 +137,24 @@ const create = (element, parent, key, options = {}) => {
124
137
  element.log = log
125
138
  }
126
139
 
127
- // console.group(element.key)
128
-
129
- // enable TRANSFORM in data
130
- if (!element.transform) element.transform = {}
131
-
132
- // enable CACHING
133
- if (!element.__cached) element.__cached = {}
134
140
 
135
- // enable EXEC
136
- if (!element.__exec) element.__exec = {}
137
-
138
- // enable CLASS CACHING
139
- if (!element.__class) element.__class = {}
140
-
141
- // enable CHANGES storing
142
- if (!element.__changes) element.__changes = []
141
+ // enable STATE
142
+ element.state = createState(element, parent)
143
143
 
144
- // enable CHANGES storing
145
- if (!element.__children) element.__children = []
144
+ // don't render IF in condition
145
+ if (isFunction(element.if)) {
146
+ // TODO: move as fragment
147
+ if (!element.if(element, element.state)) {
148
+ const ifFragment = cacheNode({ tag: 'fragment' })
149
+ element.__ifFragment = appendNode(ifFragment, parent.node)
150
+ element.__ifFalsy = true
151
+ }
152
+ }
146
153
 
147
- // Add _root element property
148
- const hasRoot = parent.parent && parent.parent.key === ':root'
149
- if (!element.__root) element.__root = hasRoot ? parent : parent.__root
154
+ // if it already HAS a NODE
155
+ if (element.node && !element.__ifFalsy) { // TODO: check on if
156
+ return assignNode(element, parent, assignedKey)
157
+ }
150
158
 
151
159
  // apply props settings
152
160
  if (!element.__ifFalsy) createProps(element, parent)
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { isFunction, isObject, isObjectLike } from '../utils'
4
4
  import { registry } from './mixins'
5
+ import root from './root'
5
6
  import { removeContentElement } from './set'
6
7
 
7
8
  const ENV = process.env.NODE_ENV
@@ -20,6 +21,24 @@ export const lookup = function (key) {
20
21
  return parent
21
22
  }
22
23
 
24
+ // TODO: update these files
25
+ export const spotByPath = function (path) {
26
+ const element = this
27
+ const arr = [].concat(path)
28
+ let active = root[arr[0]]
29
+
30
+ if (!arr || !arr.length) return console.log(arr, 'on', element.key, 'is undefined')
31
+
32
+ while (active.key === arr[0]) {
33
+ arr.shift()
34
+ if (!arr.length) break
35
+ active = active[arr[0]]
36
+ if (!active) return
37
+ }
38
+
39
+ return active
40
+ }
41
+
23
42
  export const remove = function (params) {
24
43
  const element = this
25
44
  if (isFunction(element.node.remove)) element.node.remove()
@@ -104,6 +123,7 @@ export const isMethod = function (param) {
104
123
  param === 'remove' ||
105
124
  param === 'removeContent' ||
106
125
  param === 'lookup' ||
126
+ param === 'spotByPath' ||
107
127
  param === 'keys' ||
108
128
  param === 'parse' ||
109
129
  param === 'setProps' ||
@@ -6,13 +6,16 @@ import { exec, report } from '../../utils'
6
6
  * Recursively add attributes to a DOM node
7
7
  */
8
8
  export default (params, element, node) => {
9
+ const { __attr } = element
9
10
  if (params) {
10
11
  if (!(typeof params === 'object')) report('HTMLInvalidAttr', params)
11
12
  for (const attr in params) {
12
13
  // if (!node) node = element.node
13
14
  const val = exec(params[attr], element)
15
+ if (__attr[attr] === val) return
14
16
  if (val && node.setAttribute) node.setAttribute(attr, val)
15
17
  else if (node.removeAttribute) node.removeAttribute(attr)
18
+ __attr[attr] = val
16
19
  }
17
20
  }
18
21
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  import set from '../set'
4
+ import { isEqualDeep } from '../../utils'
4
5
 
5
6
  /**
6
7
  * Appends anything as content
@@ -8,9 +9,11 @@ import set from '../set'
8
9
  */
9
10
  export default (param, element, node, options) => {
10
11
  if (param && element) {
12
+ const {$setStateCollection} = element
13
+ // console.log($setStateCollection)
11
14
  if (param.__hash === element.content.__hash && element.content.update) {
15
+ // if ($setStateCollection) return
12
16
  const { define } = element
13
- // if (define && !define.$setStateCollection)
14
17
  element.content.update(param)
15
18
  } else {
16
19
  set.call(element, param, options)
@@ -8,7 +8,7 @@ import { exec } from '../../utils'
8
8
  */
9
9
  export default (param, element, node) => {
10
10
  const prop = exec(param, element)
11
- if (prop || prop !== element.__html) {
11
+ if (prop !== element.__html) {
12
12
  // const parser = new window.DOMParser()
13
13
  // param = parser.parseFromString(param, 'text/html')
14
14
  if (node.nodeName === 'SVG') node.textContent = prop
@@ -42,9 +42,11 @@ export default {
42
42
  __ifFalsy: {},
43
43
  __text: {},
44
44
  __element: {},
45
- __class: {},
46
45
  __html: {},
46
+ __class: {},
47
47
  __className: {},
48
+ __classNames: {},
49
+ __attr: {},
48
50
  key: {},
49
51
  tag: {},
50
52
  parent: {},
@@ -55,11 +57,12 @@ export default {
55
57
  remove: {},
56
58
  removeContent: {},
57
59
  lookup: {},
60
+ spot: {},
58
61
  keys: {},
59
62
  log: {},
60
63
  parse: {},
61
64
  parseDeep: {},
62
65
  on: {},
63
66
  component: {},
64
- context: {}
67
+ context: {},
65
68
  }
@@ -1,13 +1,14 @@
1
1
  'use strict'
2
2
 
3
3
  import { exec, isObject } from '../../utils'
4
+ import { IGNORE_STATE_PARAMS } from '../state'
4
5
 
5
6
  export default (params, element, node) => {
6
7
  const state = exec(params, element)
7
8
 
8
9
  if (isObject(state)) {
9
10
  for (const param in state) {
10
- if (param === 'update' || param === '__element' || param === 'parse') continue
11
+ if (IGNORE_STATE_PARAMS.includes(param)) continue
11
12
  element.state[param] = exec(state[param], element)
12
13
  }
13
14
  }
@@ -7,11 +7,28 @@ import { exec } from '../../utils'
7
7
  * Creates a text node and appends into
8
8
  * an original one as a child
9
9
  */
10
+ export const asd = (param, element, node) => {
11
+ const prop = exec(param, element)
12
+ if (element.tag === 'string') {
13
+ node.nodeValue = prop
14
+ }
15
+ else if (param !== undefined || param !== null) {
16
+ if (element.__text && element.__text.text !== prop) return
17
+ element.__text.text = prop
18
+ if (element.__text.node) element.__text.node.nodeValue = prop
19
+ else create({ tag: 'string', text: prop }, element, '__text')
20
+ }
21
+ }
22
+
10
23
  export default (param, element, node) => {
11
24
  const prop = exec(param, element)
12
- if (element.tag === 'string') node.nodeValue = prop
25
+ if (element.tag === 'string') {
26
+ if (element.text === prop) return
27
+ node.nodeValue = prop
28
+ }
13
29
  else if (param !== undefined || param !== null) {
14
30
  if (element.__text) {
31
+ if (element.__text.text === prop) return
15
32
  element.__text.text = prop
16
33
  if (element.__text.node) element.__text.node.nodeValue = prop
17
34
  } else create({ tag: 'string', text: prop }, element, '__text')
@@ -15,12 +15,14 @@ const initProps = (element, parent) => {
15
15
  return propValue
16
16
  }
17
17
 
18
+ if (isObject(props)) {
19
+ propsStack.push(props)
20
+ }
21
+
18
22
  if (matchParent && props !== 'match') propsStack.push(matchParent)
19
23
  if (matchParentChild) propsStack.push(matchParentChild)
20
24
 
21
- if (isObject(props)) {
22
- propsStack.push(props)
23
- } else if (props === 'inherit') {
25
+ if (props === 'inherit') {
24
26
  if (parent.props) propsStack.push(parent.props)
25
27
  } else if (isMatch) {
26
28
  const hasArg = props.split(' ')
@@ -26,10 +26,10 @@ const set = function (params, options, el) {
26
26
  const element = el || this
27
27
 
28
28
  const isEqual = isEqualDeep(params, element.content)
29
+ console.error(isEqual)
30
+ console.log(element.path)
31
+ // console.error(params)
29
32
  if (isEqual && element.content.__cached) return element
30
-
31
- // console.group(element.key)
32
- // console.log(isEqual, params, element.content)
33
33
  removeContentElement(element)
34
34
 
35
35
  if (params) {
@@ -40,7 +40,6 @@ const set = function (params, options, el) {
40
40
  ...registry.defaultOptions
41
41
  })
42
42
  }
43
- // console.groupEnd(element.key)
44
43
 
45
44
  return element
46
45
  }
@@ -1,19 +1,32 @@
1
1
  'use strict'
2
2
 
3
+ import { update } from '.'
3
4
  import { on } from '../event'
4
- import { deepClone, exec, isFunction, overwriteDeep } from '../utils'
5
+ import { debounce, deepClone, exec, isFunction, isObject, overwriteDeep } from '../utils'
6
+
7
+ export const IGNORE_STATE_PARAMS = ['update', 'parse', 'clean', 'parent', '__element', '__depends', '__ref']
5
8
 
6
9
  export const parseState = function () {
7
10
  const state = this
8
11
  const parseState = {}
9
12
  for (const param in state) {
10
- if (param !== '__element' && param !== 'update' && param !== 'parse') {
13
+ if (!IGNORE_STATE_PARAMS.includes(param)) {
11
14
  parseState[param] = state[param]
12
15
  }
13
16
  }
14
17
  return parseState
15
18
  }
16
19
 
20
+ export const cleanState = function () {
21
+ const state = this
22
+ for (const param in state) {
23
+ if (!IGNORE_STATE_PARAMS.includes(param)) {
24
+ delete state[param]
25
+ }
26
+ }
27
+ return state
28
+ }
29
+
17
30
  export const updateState = function (obj, options = {}) {
18
31
  const state = this
19
32
  const element = state.__element
@@ -23,9 +36,20 @@ export const updateState = function (obj, options = {}) {
23
36
  on.initStateUpdated(element.on.initStateUpdated, element, state)
24
37
  }
25
38
 
26
- overwriteDeep(state, obj, ['update', 'parse', '__element'])
39
+ overwriteDeep(state, obj, IGNORE_STATE_PARAMS)
27
40
 
28
- if (!options.preventUpdate) element.update({}, options)
41
+ if (!options.preventUpdate) debounce(element, update, 150)({}, {
42
+ preventStateUpdate: 'once',
43
+ ...options
44
+ })
45
+
46
+ if (state.__depends) {
47
+ for (const el in state.__depends) {
48
+ // const findElement = element.spotByPath(state.__depends[el])
49
+ const findElement = state.__depends[el]
50
+ findElement.clean().update(state.parse(), options)
51
+ }
52
+ }
29
53
 
30
54
  // run `on.stateUpdated`
31
55
  if (element.on && isFunction(element.on.stateUpdated)) {
@@ -35,15 +59,27 @@ export const updateState = function (obj, options = {}) {
35
59
 
36
60
  export default function (element, parent) {
37
61
  let { state } = element
38
- // if (!state) return (parent && parent.state) || {}
62
+
39
63
  if (!state) {
40
64
  if (parent && parent.state) return parent.state
41
65
  return {}
42
66
  }
67
+
43
68
  if (isFunction(state)) state = exec(state, element)
44
69
 
45
- element.state = state = deepClone(state, ['update', 'parse', '__element'])
70
+ const { __ref } = state
71
+ if (__ref) {
72
+ state = deepClone(__ref, IGNORE_STATE_PARAMS)
73
+ if (isObject(__ref.__depends)) {
74
+ __ref.__depends[element.key] = state
75
+ } else __ref.__depends = { [element.key] : state }
76
+ } else {
77
+ state = deepClone(state, IGNORE_STATE_PARAMS)
78
+ }
79
+
80
+ element.state = state
46
81
  state.__element = element
82
+ state.clean = cleanState
47
83
  state.parse = parseState
48
84
  state.update = updateState
49
85
  state.parent = element.parent.state
@@ -11,6 +11,8 @@ import { createNode } from '.'
11
11
  import { updateProps } from './props'
12
12
  import createState from './state'
13
13
 
14
+ import { measure } from '@domql/performance'
15
+
14
16
  const UPDATE_DEFAULT_OPTIONS = {
15
17
  stackChanges: false,
16
18
  cleanExec: true,
@@ -62,26 +64,31 @@ const update = function (params = {}, options = UPDATE_DEFAULT_OPTIONS) {
62
64
  on.initUpdate(element.on.initUpdate, element, element.state)
63
65
  }
64
66
 
65
-
66
67
  for (const param in element) {
67
68
  const prop = element[param]
68
69
 
69
- if (options.preventDefineUpdate === true || options.preventDefineUpdate === param) continue
70
- if (options.preventContentUpdate && param === 'content') continue
71
- if (isMethod(param) || isObject(registry[param]) || prop === undefined) continue
70
+ if (
71
+ options.preventDefineUpdate === true || options.preventDefineUpdate === param ||
72
+ options.preventContentUpdate && param === 'content' ||
73
+ options.preventStateUpdate && param === 'state' ||
74
+ isMethod(param) || isObject(registry[param]) || prop === undefined
75
+ ) continue
76
+ if (options.preventStateUpdate === 'once') options.preventStateUpdate = false
72
77
 
73
78
  const hasDefined = define && define[param]
74
79
  const ourParam = registry[param]
75
80
 
76
- if (options.preventContentUpdate && param === 'content') console.log(param)
77
-
78
81
  if (ourParam) {
79
- // measure([element.key, param], () => {
80
- if (isFunction(ourParam)) ourParam(prop, element, node)
81
- // }, { logLevel: 5 })
82
+ if (isFunction(ourParam)) {
83
+ // console.log(param)
84
+ ourParam(prop, element, node)
85
+ }
82
86
  } else if (prop && isObject(prop) && !hasDefined) {
83
87
  if (!options.preventRecursive) {
84
- update.call(prop, params[prop], UPDATE_DEFAULT_OPTIONS)
88
+ const callChildUpdate = () => update.call(prop, params[prop], options)
89
+ if (element.props.lazyLoad || options.lazyLoad) {
90
+ window.requestAnimationFrame(() => callChildUpdate())
91
+ } else callChildUpdate()
85
92
  }
86
93
  }
87
94
  }
@@ -16,6 +16,14 @@ export const memoize = (fn) => {
16
16
  }
17
17
  }
18
18
 
19
+ export const debounce = (element, func, timeout = 300) => {
20
+ let timer;
21
+ return (...args) => {
22
+ clearTimeout(timer);
23
+ timer = setTimeout(() => { func.apply(element, args) }, timeout);
24
+ };
25
+ }
26
+
19
27
  export const isTagRegistered = arg => nodes.body.indexOf(arg)
20
28
 
21
29
  export const isObject = arg => {