diff --git a/examples/html-editor/index.js b/examples/html-editor/index.js
index 946fdb3a..80623031 100644
--- a/examples/html-editor/index.js
+++ b/examples/html-editor/index.js
@@ -1,7 +1,7 @@
/* global Y */
window.onload = function () {
- window.yXmlType.bindToDom(document.body)
+ window.domBinding = new Y.DomBinding(window.yXmlType, document.body)
}
let y = new Y('htmleditor', {
diff --git a/package-lock.json b/package-lock.json
index cdd94b4b..33bed4c4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
"integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
+ "dev": true,
"optional": true
},
"accepts": {
@@ -30,6 +31,7 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz",
"integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=",
+ "dev": true,
"optional": true,
"requires": {
"acorn": "2.7.0"
@@ -39,6 +41,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
"integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=",
+ "dev": true,
"optional": true
}
}
@@ -96,12 +99,14 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
},
"anymatch": {
"version": "1.3.0",
@@ -205,12 +210,14 @@
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
+ "dev": true,
"optional": true
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
},
"async-array-reduce": {
"version": "0.2.1",
@@ -228,18 +235,21 @@
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true,
"optional": true
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true,
"optional": true
},
"aws4": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
+ "dev": true,
"optional": true
},
"babel-cli": {
@@ -460,6 +470,7 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+ "dev": true,
"requires": {
"babel-runtime": "6.23.0"
}
@@ -876,6 +887,7 @@
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
"integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=",
+ "dev": true,
"requires": {
"core-js": "2.4.1",
"regenerator-runtime": "0.10.5"
@@ -915,6 +927,7 @@
"version": "6.25.0",
"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
"integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=",
+ "dev": true,
"requires": {
"babel-runtime": "6.23.0",
"esutils": "2.0.2",
@@ -950,6 +963,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
+ "dev": true,
"optional": true,
"requires": {
"tweetnacl": "0.14.5"
@@ -970,12 +984,14 @@
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
- "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+ "dev": true
},
"boom": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
+ "dev": true,
"optional": true,
"requires": {
"hoek": "4.2.1"
@@ -1068,6 +1084,7 @@
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true,
"optional": true
},
"center-align": {
@@ -1092,6 +1109,7 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
"requires": {
"ansi-styles": "2.2.1",
"escape-string-regexp": "1.0.5",
@@ -1110,6 +1128,7 @@
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
"integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=",
+ "dev": true,
"requires": {
"css-select": "1.2.0",
"dom-serializer": "0.1.0",
@@ -1137,6 +1156,7 @@
"requires": {
"anymatch": "1.3.0",
"async-each": "1.0.1",
+ "fsevents": "1.1.3",
"glob-parent": "2.0.0",
"inherits": "2.0.3",
"is-binary-path": "1.0.1",
@@ -1186,7 +1206,8 @@
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+ "dev": true
},
"code-point-at": {
"version": "1.1.0",
@@ -1197,12 +1218,14 @@
"color-logger": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/color-logger/-/color-logger-0.0.3.tgz",
- "integrity": "sha1-2bIt0dlz4Waxi/MT+fSBu6TfIBg="
+ "integrity": "sha1-2bIt0dlz4Waxi/MT+fSBu6TfIBg=",
+ "dev": true
},
"combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
+ "dev": true,
"requires": {
"delayed-stream": "1.0.0"
}
@@ -1361,17 +1384,20 @@
"core-js": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
- "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4="
+ "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=",
+ "dev": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
},
"cryptiles": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
+ "dev": true,
"optional": true,
"requires": {
"boom": "5.2.0"
@@ -1381,6 +1407,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
+ "dev": true,
"optional": true,
"requires": {
"hoek": "4.2.1"
@@ -1392,6 +1419,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
+ "dev": true,
"requires": {
"boolbase": "1.0.0",
"css-what": "2.1.0",
@@ -1402,17 +1430,20 @@
"css-what": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
- "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0="
+ "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=",
+ "dev": true
},
"cssom": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz",
- "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs="
+ "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=",
+ "dev": true
},
"cssstyle": {
"version": "0.2.37",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
"integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
+ "dev": true,
"optional": true,
"requires": {
"cssom": "0.3.2"
@@ -1451,6 +1482,7 @@
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
@@ -1491,7 +1523,8 @@
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
- "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+ "dev": true
},
"define-properties": {
"version": "1.1.2",
@@ -1535,7 +1568,8 @@
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
},
"depd": {
"version": "1.1.0",
@@ -1553,6 +1587,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
"integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+ "dev": true,
"requires": {
"repeating": "2.0.1"
}
@@ -1571,6 +1606,7 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
+ "dev": true,
"requires": {
"domelementtype": "1.1.3",
"entities": "1.1.1"
@@ -1579,19 +1615,22 @@
"domelementtype": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
- "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
+ "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
+ "dev": true
}
}
},
"domelementtype": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
- "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
+ "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
+ "dev": true
},
"domhandler": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
"integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",
+ "dev": true,
"requires": {
"domelementtype": "1.3.0"
}
@@ -1600,6 +1639,7 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+ "dev": true,
"requires": {
"dom-serializer": "0.1.0",
"domelementtype": "1.3.0"
@@ -1615,6 +1655,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+ "dev": true,
"optional": true,
"requires": {
"jsbn": "0.1.1"
@@ -1635,7 +1676,8 @@
"entities": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
- "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
+ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
+ "dev": true
},
"error-ex": {
"version": "1.3.1",
@@ -1751,17 +1793,20 @@
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
},
"escodegen": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz",
"integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==",
+ "dev": true,
"optional": true,
"requires": {
"esprima": "3.1.3",
@@ -1775,6 +1820,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
"optional": true
}
}
@@ -1795,6 +1841,7 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/esdoc/-/esdoc-1.0.4.tgz",
"integrity": "sha512-Hy5sg0Lec4EDHVem3gFqNi+o6ZptivmaiHYacZhmn3hzLnHSMg2C1L0XTsDIcb4Cxd9aUnWdLAu6a6ghH/LLug==",
+ "dev": true,
"requires": {
"babel-generator": "6.26.0",
"babel-traverse": "6.26.0",
@@ -1813,6 +1860,7 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
"requires": {
"chalk": "1.1.3",
"esutils": "2.0.2",
@@ -1823,6 +1871,7 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz",
"integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=",
+ "dev": true,
"requires": {
"babel-messages": "6.23.0",
"babel-runtime": "6.26.0",
@@ -1838,6 +1887,7 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
"requires": {
"core-js": "2.4.1",
"regenerator-runtime": "0.11.1"
@@ -1847,6 +1897,7 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
"integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
"requires": {
"babel-code-frame": "6.26.0",
"babel-messages": "6.23.0",
@@ -1863,6 +1914,7 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
"integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
"requires": {
"babel-runtime": "6.26.0",
"esutils": "2.0.2",
@@ -1873,29 +1925,34 @@
"babylon": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+ "dev": true
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
- "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "dev": true
}
}
},
"esdoc-accessor-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-accessor-plugin/-/esdoc-accessor-plugin-1.0.0.tgz",
- "integrity": "sha1-eRukhy5sQDUVznSbE0jW8Ck62es="
+ "integrity": "sha1-eRukhy5sQDUVznSbE0jW8Ck62es=",
+ "dev": true
},
"esdoc-brand-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-brand-plugin/-/esdoc-brand-plugin-1.0.0.tgz",
"integrity": "sha1-niFtc15i/OxJ96M5u0Eh2mfMYDM=",
+ "dev": true,
"requires": {
"cheerio": "0.22.0"
}
@@ -1903,12 +1960,14 @@
"esdoc-coverage-plugin": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/esdoc-coverage-plugin/-/esdoc-coverage-plugin-1.1.0.tgz",
- "integrity": "sha1-OGmGnNf4eJH5cmJXh2laKZrs5Fw="
+ "integrity": "sha1-OGmGnNf4eJH5cmJXh2laKZrs5Fw=",
+ "dev": true
},
"esdoc-external-ecmascript-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-external-ecmascript-plugin/-/esdoc-external-ecmascript-plugin-1.0.0.tgz",
"integrity": "sha1-ePVl1KDFGFrGMVJhTc4f4ahmiNs=",
+ "dev": true,
"requires": {
"fs-extra": "1.0.0"
}
@@ -1916,22 +1975,26 @@
"esdoc-integrate-manual-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-integrate-manual-plugin/-/esdoc-integrate-manual-plugin-1.0.0.tgz",
- "integrity": "sha1-GFSmqhwIEDXXyMUeO91PtlqkcRw="
+ "integrity": "sha1-GFSmqhwIEDXXyMUeO91PtlqkcRw=",
+ "dev": true
},
"esdoc-integrate-test-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-integrate-test-plugin/-/esdoc-integrate-test-plugin-1.0.0.tgz",
- "integrity": "sha1-4tDQAJD38MNeXS8sAzMnp55T5Ak="
+ "integrity": "sha1-4tDQAJD38MNeXS8sAzMnp55T5Ak=",
+ "dev": true
},
"esdoc-lint-plugin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/esdoc-lint-plugin/-/esdoc-lint-plugin-1.0.1.tgz",
- "integrity": "sha1-h77mQD5nbAh/Yb6SxFLWDyxqcOU="
+ "integrity": "sha1-h77mQD5nbAh/Yb6SxFLWDyxqcOU=",
+ "dev": true
},
"esdoc-publish-html-plugin": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/esdoc-publish-html-plugin/-/esdoc-publish-html-plugin-1.1.0.tgz",
"integrity": "sha1-CT+DN6yhaQIlcss4f/zD9HCwJRM=",
+ "dev": true,
"requires": {
"babel-generator": "6.11.4",
"cheerio": "0.22.0",
@@ -1946,6 +2009,7 @@
"version": "6.11.4",
"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.4.tgz",
"integrity": "sha1-FPaTOrsgxiZm0n47e59bncBxKpo=",
+ "dev": true,
"requires": {
"babel-messages": "6.23.0",
"babel-runtime": "6.23.0",
@@ -1959,6 +2023,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz",
"integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=",
+ "dev": true,
"requires": {
"get-stdin": "4.0.1",
"minimist": "1.2.0",
@@ -1968,17 +2033,20 @@
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
- "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
+ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+ "dev": true
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
},
"repeating": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz",
"integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=",
+ "dev": true,
"requires": {
"is-finite": "1.0.2"
}
@@ -1989,6 +2057,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-standard-plugin/-/esdoc-standard-plugin-1.0.0.tgz",
"integrity": "sha1-ZhIBysfvhokkkCRG/awVJyU8XU0=",
+ "dev": true,
"requires": {
"esdoc-accessor-plugin": "1.0.0",
"esdoc-brand-plugin": "1.0.0",
@@ -2006,17 +2075,20 @@
"esdoc-type-inference-plugin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/esdoc-type-inference-plugin/-/esdoc-type-inference-plugin-1.0.1.tgz",
- "integrity": "sha1-qrynhkH5m9Hs5vMC8EW71jG+cvU="
+ "integrity": "sha1-qrynhkH5m9Hs5vMC8EW71jG+cvU=",
+ "dev": true
},
"esdoc-undocumented-identifier-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-undocumented-identifier-plugin/-/esdoc-undocumented-identifier-plugin-1.0.0.tgz",
- "integrity": "sha1-guBdNxwy0ShxFA8dXIHsmf2cwsg="
+ "integrity": "sha1-guBdNxwy0ShxFA8dXIHsmf2cwsg=",
+ "dev": true
},
"esdoc-unexported-identifier-plugin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esdoc-unexported-identifier-plugin/-/esdoc-unexported-identifier-plugin-1.0.0.tgz",
- "integrity": "sha1-H5h0xqfCvr+a05fDzrdcnGnaurE="
+ "integrity": "sha1-H5h0xqfCvr+a05fDzrdcnGnaurE=",
+ "dev": true
},
"eslint": {
"version": "3.19.0",
@@ -2206,7 +2278,8 @@
"esprima": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
- "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+ "dev": true
},
"esquery": {
"version": "1.0.0",
@@ -2230,7 +2303,8 @@
"estraverse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
- "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
+ "dev": true
},
"estree-walker": {
"version": "0.2.1",
@@ -2241,7 +2315,8 @@
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
- "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+ "dev": true
},
"event-emitter": {
"version": "0.3.5",
@@ -2295,7 +2370,8 @@
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
- "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
+ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
+ "dev": true
},
"extend-shallow": {
"version": "2.0.1",
@@ -2318,7 +2394,8 @@
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
},
"ez-async": {
"version": "1.0.0-alpha.1",
@@ -2330,6 +2407,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
+ "dev": true,
"optional": true
},
"fast-diff": {
@@ -2342,12 +2420,14 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+ "dev": true,
"optional": true
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
+ "dev": true
},
"faye-websocket": {
"version": "0.11.1",
@@ -2480,12 +2560,14 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true,
"optional": true
},
"form-data": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
+ "dev": true,
"optional": true,
"requires": {
"asynckit": "0.4.0",
@@ -2509,6 +2591,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
"integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
+ "dev": true,
"requires": {
"graceful-fs": "4.1.11",
"jsonfile": "2.4.0",
@@ -2527,6 +2610,910 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
+ "fsevents": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz",
+ "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "nan": "2.9.2",
+ "node-pre-gyp": "0.6.39"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "ajv": {
+ "version": "4.11.8",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "co": "4.6.0",
+ "json-stable-stringify": "1.0.1"
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "aproba": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "delegates": "1.0.0",
+ "readable-stream": "2.2.9"
+ }
+ },
+ "asn1": {
+ "version": "0.2.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "assert-plus": {
+ "version": "0.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "aws-sign2": {
+ "version": "0.6.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "aws4": {
+ "version": "1.6.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "balanced-match": {
+ "version": "0.4.2",
+ "bundled": true,
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "tweetnacl": "0.14.5"
+ }
+ },
+ "block-stream": {
+ "version": "0.0.9",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
+ },
+ "boom": {
+ "version": "2.10.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.7",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "balanced-match": "0.4.2",
+ "concat-map": "0.0.1"
+ }
+ },
+ "buffer-shims": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "co": {
+ "version": "4.6.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "delayed-stream": "1.0.0"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "cryptiles": {
+ "version": "2.0.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "boom": "2.10.1"
+ }
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "debug": {
+ "version": "2.6.8",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.4.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "detect-libc": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "ecc-jsbn": {
+ "version": "0.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
+ },
+ "extend": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "extsprintf": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "form-data": {
+ "version": "2.1.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.5",
+ "mime-types": "2.1.15"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "fstream": {
+ "version": "1.0.11",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "inherits": "2.0.3",
+ "mkdirp": "0.5.1",
+ "rimraf": "2.6.1"
+ }
+ },
+ "fstream-ignore": {
+ "version": "1.0.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fstream": "1.0.11",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4"
+ }
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aproba": "1.1.1",
+ "console-control-strings": "1.1.0",
+ "has-unicode": "2.0.1",
+ "object-assign": "4.1.1",
+ "signal-exit": "3.0.2",
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1",
+ "wide-align": "1.1.2"
+ }
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.11",
+ "bundled": true,
+ "dev": true
+ },
+ "har-schema": {
+ "version": "1.0.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "har-validator": {
+ "version": "4.2.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "har-schema": "1.0.5"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "hawk": {
+ "version": "3.1.3",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "boom": "2.10.1",
+ "cryptiles": "2.0.5",
+ "hoek": "2.16.3",
+ "sntp": "1.0.9"
+ }
+ },
+ "hoek": {
+ "version": "2.16.3",
+ "bundled": true,
+ "dev": true
+ },
+ "http-signature": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "0.2.0",
+ "jsprim": "1.4.0",
+ "sshpk": "1.13.0"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "bundled": true,
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "jodid25519": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "jsprim": {
+ "version": "1.4.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.0.2",
+ "json-schema": "0.2.3",
+ "verror": "1.3.6"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "mime-db": {
+ "version": "1.27.0",
+ "bundled": true,
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.15",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "mime-db": "1.27.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "brace-expansion": "1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true,
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "node-pre-gyp": {
+ "version": "0.6.39",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "detect-libc": "1.0.2",
+ "hawk": "3.1.3",
+ "mkdirp": "0.5.1",
+ "nopt": "4.0.1",
+ "npmlog": "4.1.0",
+ "rc": "1.2.1",
+ "request": "2.81.0",
+ "rimraf": "2.6.1",
+ "semver": "5.3.0",
+ "tar": "2.2.1",
+ "tar-pack": "3.4.0"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "abbrev": "1.1.0",
+ "osenv": "0.1.4"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "1.1.4",
+ "console-control-strings": "1.1.0",
+ "gauge": "2.7.4",
+ "set-blocking": "2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "oauth-sign": {
+ "version": "0.8.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "wrappy": "1.0.2"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "osenv": {
+ "version": "0.1.4",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "os-homedir": "1.0.2",
+ "os-tmpdir": "1.0.2"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "performance-now": {
+ "version": "0.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "process-nextick-args": {
+ "version": "1.0.7",
+ "bundled": true,
+ "dev": true
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "qs": {
+ "version": "6.4.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "rc": {
+ "version": "1.2.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "deep-extend": "0.4.2",
+ "ini": "1.3.4",
+ "minimist": "1.2.0",
+ "strip-json-comments": "2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.2.9",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "buffer-shims": "1.0.0",
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "string_decoder": "1.0.1",
+ "util-deprecate": "1.0.2"
+ }
+ },
+ "request": {
+ "version": "2.81.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "aws-sign2": "0.6.0",
+ "aws4": "1.6.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.5",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.1.4",
+ "har-validator": "4.2.1",
+ "hawk": "3.1.3",
+ "http-signature": "1.1.1",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.15",
+ "oauth-sign": "0.8.2",
+ "performance-now": "0.2.0",
+ "qs": "6.4.0",
+ "safe-buffer": "5.0.1",
+ "stringstream": "0.0.5",
+ "tough-cookie": "2.3.2",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "semver": {
+ "version": "5.3.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "sntp": {
+ "version": "1.0.9",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
+ },
+ "sshpk": {
+ "version": "1.13.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "asn1": "0.2.3",
+ "assert-plus": "1.0.0",
+ "bcrypt-pbkdf": "1.0.1",
+ "dashdash": "1.14.1",
+ "ecc-jsbn": "0.1.1",
+ "getpass": "0.1.7",
+ "jodid25519": "1.0.2",
+ "jsbn": "0.1.1",
+ "tweetnacl": "0.14.5"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
+ },
+ "stringstream": {
+ "version": "0.0.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "tar": {
+ "version": "2.2.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "block-stream": "0.0.9",
+ "fstream": "1.0.11",
+ "inherits": "2.0.3"
+ }
+ },
+ "tar-pack": {
+ "version": "3.4.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "debug": "2.6.8",
+ "fstream": "1.0.11",
+ "fstream-ignore": "1.0.5",
+ "once": "1.4.0",
+ "readable-stream": "2.2.9",
+ "rimraf": "2.6.1",
+ "tar": "2.2.1",
+ "uid-number": "0.0.6"
+ }
+ },
+ "tough-cookie": {
+ "version": "2.3.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "punycode": "1.4.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "uid-number": {
+ "version": "0.0.6",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "uuid": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "optional": true
+ },
+ "verror": {
+ "version": "1.3.6",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extsprintf": "1.0.2"
+ }
+ },
+ "wide-align": {
+ "version": "1.1.2",
+ "bundled": true,
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "string-width": "1.0.2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ }
+ }
+ },
"function-bind": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz",
@@ -2558,6 +3545,7 @@
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0"
@@ -2621,7 +3609,8 @@
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+ "dev": true
},
"globby": {
"version": "5.0.0",
@@ -2640,7 +3629,8 @@
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
- "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
+ "dev": true
},
"graceful-readlink": {
"version": "1.0.1",
@@ -2652,12 +3642,14 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true,
"optional": true
},
"har-validator": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
+ "dev": true,
"optional": true,
"requires": {
"ajv": "5.5.2",
@@ -2668,6 +3660,7 @@
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
+ "dev": true,
"optional": true,
"requires": {
"co": "4.6.0",
@@ -2691,6 +3684,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+ "dev": true,
"requires": {
"ansi-regex": "2.1.1"
}
@@ -2714,6 +3708,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
+ "dev": true,
"optional": true,
"requires": {
"boom": "4.3.1",
@@ -2725,7 +3720,8 @@
"hoek": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
- "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
+ "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==",
+ "dev": true
},
"home-or-tmp": {
"version": "2.0.0",
@@ -2756,6 +3752,7 @@
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
+ "dev": true,
"requires": {
"domelementtype": "1.3.0",
"domhandler": "2.4.1",
@@ -2793,6 +3790,7 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
@@ -2804,6 +3802,7 @@
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/ice-cap/-/ice-cap-0.0.4.tgz",
"integrity": "sha1-im0xq0ysjUtW3k+pRt8zUlYbbhg=",
+ "dev": true,
"requires": {
"cheerio": "0.20.0",
"color-logger": "0.0.3"
@@ -2813,6 +3812,7 @@
"version": "0.20.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.20.0.tgz",
"integrity": "sha1-XHEPK6uVZTJyhCugHG6mGzVF7DU=",
+ "dev": true,
"requires": {
"css-select": "1.2.0",
"dom-serializer": "0.1.0",
@@ -2826,6 +3826,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
"integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
+ "dev": true,
"requires": {
"domelementtype": "1.3.0"
}
@@ -2834,6 +3835,7 @@
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
"integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
+ "dev": true,
"requires": {
"domelementtype": "1.3.0",
"domhandler": "2.3.0",
@@ -2845,19 +3847,22 @@
"entities": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
- "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY="
+ "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=",
+ "dev": true
}
}
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+ "dev": true,
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
@@ -2868,7 +3873,8 @@
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
+ "dev": true
}
}
},
@@ -2906,7 +3912,8 @@
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "dev": true
},
"ini": {
"version": "1.3.4",
@@ -2945,6 +3952,7 @@
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
"integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",
+ "dev": true,
"requires": {
"loose-envify": "1.3.1"
}
@@ -3022,6 +4030,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
"integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+ "dev": true,
"requires": {
"number-is-nan": "1.0.1"
}
@@ -3141,6 +4150,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true,
"optional": true
},
"is-utf8": {
@@ -3170,7 +4180,8 @@
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
},
"isexe": {
"version": "2.0.0",
@@ -3191,12 +4202,14 @@
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true,
"optional": true
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+ "dev": true
},
"js-yaml": {
"version": "3.8.4",
@@ -3212,12 +4225,14 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true,
"optional": true
},
"jsdom": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.2.tgz",
"integrity": "sha1-QLQCdwwr2iNGkJa+6Rq2deOx/G4=",
+ "dev": true,
"optional": true,
"requires": {
"abab": "1.0.4",
@@ -3241,6 +4256,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
"integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=",
+ "dev": true,
"optional": true
}
}
@@ -3248,18 +4264,21 @@
"jsesc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
- "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s="
+ "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+ "dev": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true,
"optional": true
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
+ "dev": true,
"optional": true
},
"json-stable-stringify": {
@@ -3275,6 +4294,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true,
"optional": true
},
"json5": {
@@ -3287,6 +4307,7 @@
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+ "dev": true,
"requires": {
"graceful-fs": "4.1.11"
}
@@ -3307,6 +4328,7 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
@@ -3334,6 +4356,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
"integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
+ "dev": true,
"requires": {
"graceful-fs": "4.1.11"
}
@@ -3351,6 +4374,7 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "dev": true,
"requires": {
"prelude-ls": "1.1.2",
"type-check": "0.3.2"
@@ -3530,17 +4554,20 @@
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
- "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
+ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
+ "dev": true
},
"lodash.assignin": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
- "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI="
+ "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=",
+ "dev": true
},
"lodash.bind": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
- "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
+ "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=",
+ "dev": true
},
"lodash.cond": {
"version": "4.5.2",
@@ -3551,52 +4578,62 @@
"lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
- "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
+ "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
+ "dev": true
},
"lodash.filter": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
- "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4="
+ "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=",
+ "dev": true
},
"lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
- "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
+ "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
+ "dev": true
},
"lodash.foreach": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
- "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
+ "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=",
+ "dev": true
},
"lodash.map": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
- "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
+ "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=",
+ "dev": true
},
"lodash.merge": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
- "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ=="
+ "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==",
+ "dev": true
},
"lodash.pick": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
- "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
+ "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=",
+ "dev": true
},
"lodash.reduce": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
- "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
+ "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=",
+ "dev": true
},
"lodash.reject": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
- "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU="
+ "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=",
+ "dev": true
},
"lodash.some": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
- "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
+ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=",
+ "dev": true
},
"longest": {
"version": "1.0.1",
@@ -3608,6 +4645,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
"integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+ "dev": true,
"requires": {
"js-tokens": "3.0.2"
}
@@ -3646,7 +4684,8 @@
"marked": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz",
- "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc="
+ "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=",
+ "dev": true
},
"matched": {
"version": "0.4.4",
@@ -3715,12 +4754,14 @@
"mime-db": {
"version": "1.27.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
- "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE="
+ "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=",
+ "dev": true
},
"mime-types": {
"version": "2.1.15",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
"integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
+ "dev": true,
"requires": {
"mime-db": "1.27.0"
}
@@ -3773,6 +4814,13 @@
"integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
"dev": true
},
+ "nan": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.9.2.tgz",
+ "integrity": "sha512-ltW65co7f3PQWBDbqVvaU1WtFJUsNW7sWWm4HINhbMQIyVyzIeyZ8toX5TC5eeooE6piZoaEh4cZkueSKG3KYw==",
+ "dev": true,
+ "optional": true
+ },
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -3810,6 +4858,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
+ "dev": true,
"requires": {
"boolbase": "1.0.0"
}
@@ -3817,18 +4866,21 @@
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+ "dev": true
},
"nwmatcher": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.3.tgz",
"integrity": "sha512-IKdSTiDWCarf2JTS5e9e2+5tPZGdkRJ79XjYV0pzK8Q9BpsFyBq1RGKxzs7Q8UBushGw7m6TzVKz6fcY99iSWw==",
+ "dev": true,
"optional": true
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
+ "dev": true,
"optional": true
},
"object-assign": {
@@ -3898,6 +4950,7 @@
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "dev": true,
"requires": {
"deep-is": "0.1.3",
"fast-levenshtein": "2.0.6",
@@ -3910,7 +4963,8 @@
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+ "dev": true
}
}
},
@@ -3989,6 +5043,7 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
"integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=",
+ "dev": true,
"optional": true
},
"parseurl": {
@@ -4048,6 +5103,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true,
"optional": true
},
"pify": {
@@ -4130,7 +5186,8 @@
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+ "dev": true
},
"preserve": {
"version": "0.2.0",
@@ -4147,7 +5204,8 @@
"process-nextick-args": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
- "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
+ "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+ "dev": true
},
"progress": {
"version": "1.1.8",
@@ -4158,12 +5216,14 @@
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
+ "dev": true,
"optional": true
},
"quill": {
@@ -4303,6 +5363,7 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+ "dev": true,
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
@@ -4364,7 +5425,8 @@
"regenerator-runtime": {
"version": "0.10.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
- "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
+ "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
+ "dev": true
},
"regenerator-transform": {
"version": "0.9.11",
@@ -4443,6 +5505,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+ "dev": true,
"requires": {
"is-finite": "1.0.2"
}
@@ -4451,6 +5514,7 @@
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
+ "dev": true,
"optional": true,
"requires": {
"aws-sign2": "0.7.0",
@@ -4481,12 +5545,14 @@
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
+ "dev": true,
"optional": true
},
"mime-types": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+ "dev": true,
"optional": true,
"requires": {
"mime-db": "1.33.0"
@@ -4717,12 +5783,14 @@
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+ "dev": true
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true,
"optional": true
},
"semver": {
@@ -4800,6 +5868,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
"integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
+ "dev": true,
"optional": true,
"requires": {
"hoek": "4.2.1"
@@ -4808,7 +5877,8 @@
"source-map": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
- "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI="
+ "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
+ "dev": true
},
"source-map-support": {
"version": "0.4.15",
@@ -4865,6 +5935,7 @@
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
+ "dev": true,
"optional": true,
"requires": {
"asn1": "0.2.3",
@@ -4980,6 +6051,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "dev": true,
"requires": {
"safe-buffer": "5.1.1"
}
@@ -4988,12 +6060,14 @@
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
+ "dev": true,
"optional": true
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
"requires": {
"ansi-regex": "2.1.1"
}
@@ -5030,12 +6104,14 @@
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
},
"symbol-tree": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
"integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
+ "dev": true,
"optional": true
},
"table": {
@@ -5088,7 +6164,8 @@
"taffydb": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.2.tgz",
- "integrity": "sha1-e/gQalwaSCUbPjvAoOFzJIn9Dcg="
+ "integrity": "sha1-e/gQalwaSCUbPjvAoOFzJIn9Dcg=",
+ "dev": true
},
"tag-dist-files": {
"version": "0.1.6",
@@ -5123,7 +6200,8 @@
"to-fast-properties": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
+ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+ "dev": true
},
"to-object-path": {
"version": "0.3.0",
@@ -5138,6 +6216,7 @@
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
+ "dev": true,
"requires": {
"punycode": "1.4.1"
}
@@ -5146,6 +6225,7 @@
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
+ "dev": true,
"optional": true
},
"tree-kill": {
@@ -5163,7 +6243,8 @@
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
- "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
+ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+ "dev": true
},
"tryit": {
"version": "1.0.3",
@@ -5175,6 +6256,7 @@
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
"optional": true,
"requires": {
"safe-buffer": "5.1.1"
@@ -5184,12 +6266,14 @@
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true,
"optional": true
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dev": true,
"requires": {
"prelude-ls": "1.1.2"
}
@@ -5245,7 +6329,8 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
},
"utils-merge": {
"version": "1.0.0",
@@ -5256,7 +6341,8 @@
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
- "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
+ "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
+ "dev": true
},
"v8flags": {
"version": "2.1.1",
@@ -5287,6 +6373,7 @@
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
"optional": true,
"requires": {
"assert-plus": "1.0.0",
@@ -5304,6 +6391,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz",
"integrity": "sha1-O/glj30xjHRDw28uFpQCoaZwNQY=",
+ "dev": true,
"optional": true
},
"websocket-driver": {
@@ -5325,6 +6413,7 @@
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
"integrity": "sha1-AImBEa9om7CXVBzVpFymyHmERb8=",
+ "dev": true,
"optional": true,
"requires": {
"tr46": "0.0.3"
@@ -5370,6 +6459,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
"integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
+ "dev": true,
"optional": true
},
"xtend": {
diff --git a/package.json b/package.json
index 4a48e265..484e811b 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"test": "npm run lint",
"debug": "concurrently 'rollup -wc rollup.test.js' 'cutest-serve y.test.js -o'",
"lint": "standard",
- "docs": "esdocs",
+ "docs": "esdoc",
"serve-docs": "npm run docs && serve ./docs/",
"dist": "rollup -c rollup.browser.js; rollup -c rollup.node.js",
"watch": "concurrently 'rollup -wc rollup.browser.js' 'rollup -wc rollup.node.js'",
@@ -56,6 +56,8 @@
"chance": "^1.0.9",
"concurrently": "^3.4.0",
"cutest": "^0.1.9",
+ "esdoc": "^1.0.4",
+ "esdoc-standard-plugin": "^1.0.0",
"quill": "^1.3.5",
"quill-cursors": "^1.0.2",
"rollup-plugin-babel": "^2.7.1",
@@ -67,9 +69,7 @@
"rollup-regenerator-runtime": "^6.23.1",
"rollup-watch": "^3.2.2",
"standard": "^10.0.2",
- "tag-dist-files": "^0.1.6",
- "esdoc": "^1.0.4",
- "esdoc-standard-plugin": "^1.0.0"
+ "tag-dist-files": "^0.1.6"
},
"dependencies": {
"debug": "^2.6.8"
diff --git a/rollup.browser.js b/rollup.browser.js
index d5f6c137..a0b87065 100644
--- a/rollup.browser.js
+++ b/rollup.browser.js
@@ -19,7 +19,8 @@ export default {
browser: true
}),
commonjs(),
- babel(),
+ // babel(),
+ /*
uglify({
mangle: {
except: ['YMap', 'Y', 'YArray', 'YText', 'YXmlHook', 'YXmlFragment', 'YXmlElement', 'YXmlEvent', 'YXmlText', 'YEvent', 'YArrayEvent', 'YMapEvent', 'Type', 'Delete', 'ItemJSON', 'ItemString', 'Item']
@@ -35,6 +36,7 @@ export default {
}
}
})
+ */
],
banner: `
/**
diff --git a/src/Bindings/DomBinding/DomBinding.js b/src/Bindings/DomBinding/DomBinding.js
index 06b46c1c..d8b06dab 100644
--- a/src/Bindings/DomBinding/DomBinding.js
+++ b/src/Bindings/DomBinding/DomBinding.js
@@ -1,109 +1,15 @@
/* global MutationObserver */
-import Binding from './Binding.js'
-import diff from '../Util/simpleDiff.js'
-import YXmlFragment from '../../Type/YXml/YXmlFragment.js'
-import YXmlHook from '../../Type/YXml/YXmlHook.js'
-
-
-function defaultFilter (nodeName, attrs) {
- return attrs
-}
-
-function applyFilter (target, filter, type) {
- if (type._deleted) {
- return
- }
- // check if type is a child of this
- let isChild = false
- let p = type
- while (p !== undefined) {
- if (p === target) {
- isChild = true
- break
- }
- p = p._parent
- }
- if (!isChild) {
- return
- }
- // filter attributes
- const attributes = new Map()
- if (type.getAttributes !== undefined) {
- let attrs = type.getAttributes()
- for (let key in attrs) {
- attributes.set(key, attrs[key])
- }
- }
- let result = filter(type.nodeName, new Map(attributes))
- if (result === null) {
- type._delete(this._y)
- } else {
- attributes.forEach((value, key) => {
- if (!result.has(key)) {
- type.removeAttribute(key)
- }
- })
- }
-}
-
-function typeObserver (events) {
- this._mutualExclude(() => {
- reflectChangesOnDom.call(this, events)
- })
-}
-
-function domObserver (mutations) {
- this._mutualExclude(() => {
- this._y.transact(() => {
- let diffChildren = new Set()
- mutations.forEach(mutation => {
- const dom = mutation.target
- const yxml = this.domToYXml.get(dom._yxml)
- if (yxml == null || yxml.constructor === YXmlHook) {
- // dom element is filtered
- return
- }
- switch (mutation.type) {
- case 'characterData':
- var change = diff(yxml.toString(), dom.nodeValue)
- yxml.delete(change.pos, change.remove)
- yxml.insert(change.pos, change.insert)
- break
- case 'attributes':
- if (yxml.constructor === YXmlFragment) {
- break
- }
- let name = mutation.attributeName
- let val = dom.getAttribute(name)
- // check if filter accepts attribute
- let attributes = new Map()
- attributes.set(name, val)
- if (this.filter(dom.nodeName, attributes).size > 0 && yxml.constructor !== YXmlFragment) {
- if (yxml.getAttribute(name) !== val) {
- if (val == null) {
- yxml.removeAttribute(name)
- } else {
- yxml.setAttribute(name, val)
- }
- }
- }
- break
- case 'childList':
- diffChildren.add(mutation.target)
- break
- }
- })
- for (let dom of diffChildren) {
- if (dom.yOnChildrenChanged !== undefined) {
- dom.yOnChildrenChanged()
- }
- const yxml = this.domToType.get(dom)
- applyChangesFromDom(dom, yxml)
- }
- })
- })
-}
+import Binding from '../Binding.js'
+import diff from '../../Util/simpleDiff.js'
+import YXmlFragment from '../../Types/YXml/YXmlFragment.js'
+import YXmlHook from '../../Types/YXml/YXmlHook.js'
+import { removeDomChildrenUntilElementFound, createAssociation } from './util.js'
+import { beforeTransactionSelectionFixer, afterTransactionSelectionFixer } from './selection.js'
+import { defaultFilter, applyFilterOnType } from './filter.js'
+import typeObserver from './typeObserver.js'
+import domObserver from './domObserver.js'
+import { removeAssociation } from './util.js'
/**
* A binding that binds the children of a YXmlFragment to a DOM element.
@@ -122,7 +28,7 @@ export default class DomBinding extends Binding {
* truth.
* @param {Element} target The bind target. Mirrors the target.
*/
- constructor (type, target, opts) {
+ constructor (type, target, opts = {}) {
// Binding handles textType as this.type and domTextarea as this.target
super(type, target)
this.domToType = new Map()
@@ -134,20 +40,73 @@ export default class DomBinding extends Binding {
target.insertBefore(child.toDom(this.domToType, this.typeToDom), null)
}
this._typeObserver = typeObserver.bind(this)
- this._domObserver = domObserver.bind(this)
- type.observe(this._typeObserver)
- this._domObserver = domObserver.bind(this)
- this._mutationObserver = new MutationObserver(this._domObserver())
+ this._domObserver = (mutations) => {
+ domObserver.call(this, mutations, opts._document)
+ }
+ type.observeDeep(this._typeObserver)
+ this._mutationObserver = new MutationObserver(this._domObserver)
this._mutationObserver.observe(target, {
childList: true,
attributes: true,
characterData: true,
subtree: true
})
- this._beforeTransactionHandler = () => {
- this._domObserverListener(this._domObserver.takeRecords())
+ const y = type._y
+ // Force flush dom changes before Type changes are applied (they might
+ // modify the dom)
+ this._beforeTransactionHandler = (y, transaction, remote) => {
+ this._domObserver(this._mutationObserver.takeRecords())
+ beforeTransactionSelectionFixer(y, this, transaction, remote)
}
- this._y.on('beforeTransaction', this._beforeTransactionHandler)
+ y.on('beforeTransaction', this._beforeTransactionHandler)
+ this._afterTransactionHandler = (y, transaction, remote) => {
+ afterTransactionSelectionFixer(y, this, transaction, remote)
+ // remove associations
+ // TODO: this could be done more efficiently
+ // e.g. Always delete using the following approach, or removeAssociation
+ // in dom/type-observer..
+ transaction.deletedStructs.forEach(type => {
+ const dom = this.typeToDom.get(type)
+ if (dom !== undefined) {
+ removeAssociation(this, dom, type)
+ }
+ })
+ }
+ y.on('afterTransaction', this._afterTransactionHandler)
+ // Before calling observers, apply dom filter to all changed and new types.
+ this._beforeObserverCallsHandler = (y, transaction) => {
+ // Apply dom filter to new and changed types
+ transaction.changedTypes.forEach((subs, type) => {
+ // Only check attributes. New types are filtered below.
+ if ((subs.size > 1 || (subs.size === 1 && subs.has(null) === false))) {
+ applyFilterOnType(y, this, type)
+ }
+ })
+ transaction.newTypes.forEach(type => {
+ applyFilterOnType(y, this, type)
+ })
+ }
+ y.on('beforeObserverCalls', this._beforeObserverCallsHandler)
+ createAssociation(this, target, type)
+ }
+
+ /**
+ * Enables the smart scrolling functionality for a Dom Binding.
+ * This is useful when YXml is bound to a shared editor. When activated,
+ * the viewport will be changed to accommodate remote changes.
+ *
+ * @param {Element} scrollElement The node that is
+ */
+ enableSmartScrolling (scrollElement) {
+ // @TODO: implement smart scrolling
+ }
+
+ /**
+ * NOTE: currently does not apply filter to existing elements!
+ */
+ setFilter (filter) {
+ this.filter = filter
+ // TODO: apply filter to all elements
}
/**
@@ -158,7 +117,11 @@ export default class DomBinding extends Binding {
this.typeToDom = null
this.type.unobserve(this._typeObserver)
this._mutationObserver.disconnect()
- this.type._y.off('beforeTransaction', this._beforeTransactionHandler)
+ const y = this.type._y
+ y.off('beforeTransaction', this._beforeTransactionHandler)
+ y.off('beforeObserverCalls', this._beforeObserverCallsHandler)
+ y.off('afterObserverCalls', this._afterObserverCallsHandler)
+ y.off('afterTransaction', this._afterTransactionHandler)
super.destroy()
}
}
diff --git a/src/Bindings/DomBinding/applyChangesFromDom.js b/src/Bindings/DomBinding/applyChangesFromDom.js
deleted file mode 100644
index 94578ef7..00000000
--- a/src/Bindings/DomBinding/applyChangesFromDom.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import YXmlHook from '../../YXml/YXmlHook.js'
-import {
- iterateUntilUndeleted,
- removeAssociation,
- insertNodeHelper } from './util.js'
-
-/*
- * 1. Check if any of the nodes was deleted
- * 2. Iterate over the children.
- * 2.1 If a node exists without _yxml property, insert a new node
- * 2.2 If _contents.length < dom.childNodes.length, fill the
- * rest of _content with childNodes
- * 2.3 If a node was moved, delete it and
- * recreate a new yxml element that is bound to that node.
- * You can detect that a node was moved because expectedId
- * !== actualId in the list
- */
-export default function applyChangesFromDom (dom, yxml) {
- if (yxml == null || yxml === false || yxml.constructor === YXmlHook) {
- return
- }
- const y = yxml._y
- const knownChildren = new Set()
- for (let child in dom.childNodes) {
- const type = knownChildren.get(child)
- if (type !== undefined && type !== false) {
- knownChildren.add(type)
- }
- }
- // 1. Check if any of the nodes was deleted
- yxml.forEach(function (childType) {
- if (knownChildren.has(childType) === false) {
- childType._delete(y)
- }
- })
- // 2. iterate
- const childNodes = dom.childNodes
- const len = childNodes.length
- let prevExpectedType = null
- let expectedType = iterateUntilUndeleted(yxml._start)
- for (let domCnt = 0; domCnt < len; domCnt++) {
- const childNode = childNodes[domCnt]
- const childType = this.domToYXml.get(childNode)
- if (childType != null) {
- if (childType === false) {
- // should be ignored or is going to be deleted
- continue
- }
- if (expectedType !== null) {
- if (expectedType !== childType) {
- // 2.3 Not expected node
- if (childType._parent !== yxml) {
- // child was moved from another parent
- // childType is going to be deleted by its previous parent
- removeAssociation(this, childNode, this.domToYXml(childNode))
- } else {
- // child was moved to a different position.
- childType._delete(y)
- }
- prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode)
- } else {
- // Found expected node
- prevExpectedType = expectedType
- expectedType = iterateUntilUndeleted(expectedType._right)
- }
- } else {
- // 2.2 Fill _content with child nodes
- prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode)
- }
- } else {
- // 2.1 A new node was found
- prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode)
- }
- }
-}
diff --git a/src/Bindings/DomBinding/domObserver.js b/src/Bindings/DomBinding/domObserver.js
new file mode 100644
index 00000000..f0f4d6bb
--- /dev/null
+++ b/src/Bindings/DomBinding/domObserver.js
@@ -0,0 +1,132 @@
+
+import YXmlHook from '../../Types/YXml/YXmlHook.js'
+import {
+ iterateUntilUndeleted,
+ removeAssociation,
+ insertNodeHelper } from './util.js'
+import diff from '../../Util/simpleDiff.js'
+import YXmlFragment from '../../Types/YXml/YXmlFragment.js'
+
+/*
+ * 1. Check if any of the nodes was deleted
+ * 2. Iterate over the children.
+ * 2.1 If a node exists that is not yet bound to a type, insert a new node
+ * 2.2 If _contents.length < dom.childNodes.length, fill the
+ * rest of _content with childNodes
+ * 2.3 If a node was moved, delete it and
+ * recreate a new yxml element that is bound to that node.
+ * You can detect that a node was moved because expectedId
+ * !== actualId in the list
+ */
+function applyChangesFromDom (binding, dom, yxml, _document) {
+ if (yxml == null || yxml === false || yxml.constructor === YXmlHook) {
+ return
+ }
+ const y = yxml._y
+ const knownChildren = new Set()
+ for (let i = dom.childNodes.length - 1; i >= 0; i--) {
+ const type = binding.domToType.get(dom.childNodes[i])
+ if (type !== undefined && type !== false) {
+ knownChildren.add(type)
+ }
+ }
+ // 1. Check if any of the nodes was deleted
+ yxml.forEach(function (childType) {
+ if (knownChildren.has(childType) === false) {
+ childType._delete(y)
+ removeAssociation(binding, binding.typeToDom.get(childType), childType)
+ }
+ })
+ // 2. iterate
+ const childNodes = dom.childNodes
+ const len = childNodes.length
+ let prevExpectedType = null
+ let expectedType = iterateUntilUndeleted(yxml._start)
+ for (let domCnt = 0; domCnt < len; domCnt++) {
+ const childNode = childNodes[domCnt]
+ const childType = binding.domToType.get(childNode)
+ if (childType !== undefined) {
+ if (childType === false) {
+ // should be ignored or is going to be deleted
+ continue
+ }
+ if (expectedType !== null) {
+ if (expectedType !== childType) {
+ // 2.3 Not expected node
+ if (childType._parent !== yxml) {
+ // child was moved from another parent
+ // childType is going to be deleted by its previous parent
+ removeAssociation(binding, childNode, childType)
+ } else {
+ // child was moved to a different position.
+ childType._delete(y)
+ removeAssociation(binding, childNode, childType)
+ }
+ prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
+ } else {
+ // Found expected node. Continue.
+ prevExpectedType = expectedType
+ expectedType = iterateUntilUndeleted(expectedType._right)
+ }
+ } else {
+ // 2.2 Fill _content with child nodes
+ prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
+ }
+ } else {
+ // 2.1 A new node was found
+ prevExpectedType = insertNodeHelper(yxml, prevExpectedType, childNode, _document, binding)
+ }
+ }
+}
+
+export default function domObserver (mutations, _document) {
+ this._mutualExclude(() => {
+ this.type._y.transact(() => {
+ let diffChildren = new Set()
+ mutations.forEach(mutation => {
+ const dom = mutation.target
+ const yxml = this.domToType.get(dom)
+ if (yxml === false || yxml === undefined || yxml.constructor === YXmlHook) {
+ // dom element is filtered
+ return
+ }
+ switch (mutation.type) {
+ case 'characterData':
+ var change = diff(yxml.toString(), dom.nodeValue)
+ yxml.delete(change.pos, change.remove)
+ yxml.insert(change.pos, change.insert)
+ break
+ case 'attributes':
+ if (yxml.constructor === YXmlFragment) {
+ break
+ }
+ let name = mutation.attributeName
+ let val = dom.getAttribute(name)
+ // check if filter accepts attribute
+ let attributes = new Map()
+ attributes.set(name, val)
+ if (yxml.constructor !== YXmlFragment && this.filter(dom.nodeName, attributes).size > 0) {
+ if (yxml.getAttribute(name) !== val) {
+ if (val == null) {
+ yxml.removeAttribute(name)
+ } else {
+ yxml.setAttribute(name, val)
+ }
+ }
+ }
+ break
+ case 'childList':
+ diffChildren.add(mutation.target)
+ break
+ }
+ })
+ for (let dom of diffChildren) {
+ if (dom.yOnChildrenChanged !== undefined) {
+ dom.yOnChildrenChanged()
+ }
+ const yxml = this.domToType.get(dom)
+ applyChangesFromDom(this, dom, yxml, _document)
+ }
+ })
+ })
+}
diff --git a/src/Bindings/DomBinding/domToType.js b/src/Bindings/DomBinding/domToType.js
new file mode 100644
index 00000000..ddf21a6d
--- /dev/null
+++ b/src/Bindings/DomBinding/domToType.js
@@ -0,0 +1,32 @@
+
+import { YXmlText, YXmlElement } from '../../Types/YXml/YXml.js'
+import { createAssociation } from './util.js'
+
+/**
+ * Creates a Yjs type (YXml) based on the contents of a DOM Element.
+ *
+ * @param {Element|TextNode}
+ */
+export default function domToType (element, _document = document, binding) {
+ let type
+ switch (element.nodeType) {
+ case _document.ELEMENT_NODE:
+ type = new YXmlElement(element.nodeName)
+ const attrs = element.attributes
+ for (let i = attrs.length - 1; i >= 0; i--) {
+ const attr = attrs[i]
+ type.setAttribute(attr.name, attr.value)
+ }
+ const children = Array.from(element.childNodes).map(e => domToType(e, _document, binding))
+ type.insert(0, children)
+ break
+ case _document.TEXT_NODE:
+ type = new YXmlText()
+ type.insert(0, element.nodeValue)
+ break
+ default:
+ throw new Error('Can\'t transform this node type to a YXml type!')
+ }
+ createAssociation(binding, element, type)
+ return type
+}
diff --git a/src/Bindings/DomBinding/filter.js b/src/Bindings/DomBinding/filter.js
new file mode 100644
index 00000000..e9cb8b87
--- /dev/null
+++ b/src/Bindings/DomBinding/filter.js
@@ -0,0 +1,31 @@
+import isParentOf from '../../Util/isParentOf.js'
+
+export function defaultFilter (nodeName, attrs) {
+ return attrs
+}
+
+
+export function applyFilterOnType (y, binding, type) {
+ if (isParentOf(binding.type, type)) {
+ const nodeName = type.nodeName
+ let attributes = new Map()
+ if (type.getAttributes !== undefined) {
+ let attrs = type.getAttributes()
+ for (let key in attrs) {
+ attributes.set(key, attrs[key])
+ }
+ }
+ const filteredAttributes = binding.filter(nodeName, new Map(attributes))
+ if (filteredAttributes === null) {
+ type._delete(y)
+ } else {
+ // iterate original attributes
+ attributes.forEach((value, key) => {
+ // delete all attributes that are not in filteredAttributes
+ if (filteredAttributes.has(key) === false) {
+ type.removeAttribute(key)
+ }
+ })
+ }
+ }
+}
diff --git a/src/Types/YXml/selection.js b/src/Bindings/DomBinding/selection.js
similarity index 70%
rename from src/Types/YXml/selection.js
rename to src/Bindings/DomBinding/selection.js
index 428217f0..551f4e87 100644
--- a/src/Types/YXml/selection.js
+++ b/src/Bindings/DomBinding/selection.js
@@ -7,30 +7,30 @@ let relativeSelection = null
export let beforeTransactionSelectionFixer
if (typeof getSelection !== 'undefined') {
- beforeTransactionSelectionFixer = function _beforeTransactionSelectionFixer (y, transaction, remote) {
+ beforeTransactionSelectionFixer = function _beforeTransactionSelectionFixer (y, domBinding, transaction, remote) {
if (!remote) {
return
}
relativeSelection = { from: null, to: null, fromY: null, toY: null }
browserSelection = getSelection()
const anchorNode = browserSelection.anchorNode
- if (anchorNode !== null && anchorNode._yxml != null) {
- const yxml = anchorNode._yxml
- relativeSelection.from = getRelativePosition(yxml, browserSelection.anchorOffset)
- relativeSelection.fromY = yxml._y
+ const anchorNodeType = domBinding.domToType.get(anchorNode)
+ if (anchorNode !== null && anchorNodeType !== undefined) {
+ relativeSelection.from = getRelativePosition(anchorNodeType, browserSelection.anchorOffset)
+ relativeSelection.fromY = anchorNodeType._y
}
const focusNode = browserSelection.focusNode
- if (focusNode !== null && focusNode._yxml != null) {
- const yxml = focusNode._yxml
- relativeSelection.to = getRelativePosition(yxml, browserSelection.focusOffset)
- relativeSelection.toY = yxml._y
+ const focusNodeType = domBinding.domToType.get(focusNode)
+ if (focusNode !== null && focusNodeType !== undefined) {
+ relativeSelection.to = getRelativePosition(focusNodeType, browserSelection.focusOffset)
+ relativeSelection.toY = focusNodeType._y
}
}
} else {
beforeTransactionSelectionFixer = function _fakeBeforeTransactionSelectionFixer () {}
}
-export function afterTransactionSelectionFixer (y, transaction, remote) {
+export function afterTransactionSelectionFixer (y, domBinding, transaction, remote) {
if (relativeSelection === null || !remote) {
return
}
@@ -46,7 +46,7 @@ export function afterTransactionSelectionFixer (y, transaction, remote) {
if (from !== null) {
let sel = fromRelativePosition(fromY, from)
if (sel !== null) {
- let node = sel.type.getDom()
+ let node = domBinding.typeToDom.get(sel.type)
let offset = sel.offset
if (node !== anchorNode || offset !== anchorOffset) {
anchorNode = node
@@ -58,7 +58,7 @@ export function afterTransactionSelectionFixer (y, transaction, remote) {
if (to !== null) {
let sel = fromRelativePosition(toY, to)
if (sel !== null) {
- let node = sel.type.getDom()
+ let node = domBinding.typeToDom.get(sel.type)
let offset = sel.offset
if (node !== focusNode || offset !== focusOffset) {
focusNode = node
diff --git a/src/Bindings/DomBinding/typeObserver.js b/src/Bindings/DomBinding/typeObserver.js
new file mode 100644
index 00000000..46f8c79d
--- /dev/null
+++ b/src/Bindings/DomBinding/typeObserver.js
@@ -0,0 +1,61 @@
+
+import YXmlText from '../../Types/YXml/YXmlText.js'
+import YXmlHook from '../../Types/YXml/YXmlHook.js'
+import { removeDomChildrenUntilElementFound } from './util.js'
+
+export default function typeObserver (events, _document) {
+ this._mutualExclude(() => {
+ events.forEach(event => {
+ const yxml = event.target
+ const dom = this.typeToDom.get(yxml)
+ if (dom !== undefined && dom !== false) {
+ if (yxml.constructor === YXmlText) {
+ dom.nodeValue = yxml.toString()
+ // TODO: use hasOwnProperty instead of === undefined check
+ } else if (event.attributesChanged !== undefined) {
+ // update attributes
+ event.attributesChanged.forEach(attributeName => {
+ const value = yxml.getAttribute(attributeName)
+ if (value === undefined) {
+ dom.removeAttribute(attributeName)
+ } else {
+ dom.setAttribute(attributeName, value)
+ }
+ })
+ /*
+ * TODO: instead of hard-checking the types, it would be best to
+ * specify the type's features. E.g.
+ * - _yxmlHasAttributes
+ * - _yxmlHasChildren
+ * Furthermore, the features shouldn't be encoded in the types,
+ * only in the attributes (above)
+ */
+ if (event.childListChanged && yxml.constructor !== YXmlHook) {
+ let currentChild = dom.firstChild
+ yxml.forEach(childType => {
+ const childNode = this.typeToDom.get(childType)
+ const binding = this
+ switch (childNode) {
+ case undefined:
+ // Does not exist. Create it.
+ const node = childType.toDom(_document, binding)
+ dom.insertBefore(node, currentChild)
+ break
+ case false:
+ // nop
+ break
+ default:
+ // Is already attached to the dom.
+ // Find it and remove all dom nodes in-between.
+ removeDomChildrenUntilElementFound(dom, currentChild, childNode)
+ currentChild = childNode.nextSibling
+ break
+ }
+ })
+ removeDomChildrenUntilElementFound(dom, currentChild, null)
+ }
+ }
+ }
+ })
+ })
+}
diff --git a/src/Bindings/DomBinding/util.js b/src/Bindings/DomBinding/util.js
index cc2e3e64..f8e5c94c 100644
--- a/src/Bindings/DomBinding/util.js
+++ b/src/Bindings/DomBinding/util.js
@@ -1,4 +1,6 @@
+import domToType from './domToType.js'
+
export function iterateUntilUndeleted (item) {
while (item !== null && item._deleted) {
item = item._right
@@ -12,15 +14,51 @@ export function removeAssociation (domBinding, dom, type) {
}
export function createAssociation (domBinding, dom, type) {
- domBinding.domToType.set(dom, type)
- domBinding.typeToDom.set(type, dom)
+ if (domBinding !== undefined) {
+ domBinding.domToType.set(dom, type)
+ domBinding.typeToDom.set(type, dom)
+ }
}
-function insertNodeHelper (yxml, prevExpectedNode, child) {
- let insertedNodes = yxml.insertDomElementsAfter(prevExpectedNode, [child])
+/**
+ * Insert Dom Elements after one of the children of this YXmlFragment.
+ * The Dom elements will be bound to a new YXmlElement and inserted at the
+ * specified position.
+ *
+ * @param {YXmlElement} type The type in which to insert DOM elements.
+ * @param {YXmlElement|null} prev The reference node. New YxmlElements are
+ * inserted after this node. Set null to insert at
+ * the beginning.
+ * @param {Array} doms The Dom elements to insert.
+ * @param {?Document} _document Optional. Provide the global document object.
+ * @return {Array} The YxmlElements that are inserted.
+ */
+export function insertDomElementsAfter (type, prev, doms, _document, binding) {
+ return type.insertAfter(prev, doms.map(dom => domToType(dom, _document, binding)))
+}
+
+export function insertNodeHelper (yxml, prevExpectedNode, child, _document, binding) {
+ let insertedNodes = insertDomElementsAfter(yxml, prevExpectedNode, [child], _document, binding)
if (insertedNodes.length > 0) {
return insertedNodes[0]
} else {
return prevExpectedNode
}
}
+
+
+/**
+ * Remove children until `elem` is found.
+ *
+ * @param {Element} parent The parent of `elem` and `currentChild`.
+ * @param {Element} currentChild Start removing elements with `currentChild`. If
+ * `currentChild` is `elem` it won't be removed.
+ * @param {Element|null} elem The elemnt to look for.
+ */
+export function removeDomChildrenUntilElementFound (parent, currentChild, elem) {
+ while (currentChild !== elem) {
+ const del = currentChild
+ currentChild = currentChild.nextSibling
+ parent.removeChild(del)
+ }
+}
diff --git a/src/Bindings/QuillBinding/QuillBinding.js b/src/Bindings/QuillBinding/QuillBinding.js
index e88a6c44..02995ec9 100644
--- a/src/Bindings/QuillBinding/QuillBinding.js
+++ b/src/Bindings/QuillBinding/QuillBinding.js
@@ -1,11 +1,14 @@
-import Binding from './Binding.js'
+import Binding from '../Binding.js'
function typeObserver (event) {
const quill = this.target
+ // Force flush Quill changes.
quill.update('yjs')
this._mutualExclude(function () {
+ // Apply computed delta.
quill.updateContents(event.delta, 'yjs')
- quill.update('yjs') // ignore applied changes
+ // Force flush Quill changes. Ignore applied changes.
+ quill.update('yjs')
})
}
@@ -16,12 +19,14 @@ function quillObserver (delta) {
}
/**
- * A Binding that binds a YText type to a Quill editor
+ * A Binding that binds a YText type to a Quill editor.
*
* @example
- * const quill = new Quill(document.createElement('div'))
- * const type = y.define('quill', Y.Text)
- * const binding = new Y.QuillBinding(quill, type)
+ * const quill = new Quill(document.createElement('div'))
+ * const type = y.define('quill', Y.Text)
+ * const binding = new Y.QuillBinding(quill, type)
+ * // Now modifications on the DOM will be reflected in the Type, and the other
+ * // way around!
*/
export default class QuillBinding extends Binding {
/**
@@ -29,18 +34,18 @@ export default class QuillBinding extends Binding {
* @param {Quill} quill
*/
constructor (textType, quill) {
- // Binding handles textType as this.type and quill as this.target
+ // Binding handles textType as this.type and quill as this.target.
super(textType, quill)
- // set initial value
+ // Set initial value.
quill.setContents(textType.toDelta(), 'yjs')
- // Observers are handled by this class
+ // Observers are handled by this class.
this._typeObserver = typeObserver.bind(this)
this._quillObserver = quillObserver.bind(this)
textType.observe(this._typeObserver)
quill.on('text-change', this._quillObserver)
}
destroy () {
- // Remove everything that is handled by this class
+ // Remove everything that is handled by this class.
this.type.unobserve(this._typeObserver)
this.target.off('text-change', this._quillObserver)
super.destroy()
diff --git a/src/Bindings/TextareaBinding/TextareaBinding.js b/src/Bindings/TextareaBinding/TextareaBinding.js
index b09fb0a7..e02edafe 100644
--- a/src/Bindings/TextareaBinding/TextareaBinding.js
+++ b/src/Bindings/TextareaBinding/TextareaBinding.js
@@ -1,7 +1,7 @@
-import Binding from './Binding.js'
-import simpleDiff from '../Util/simpleDiff.js'
-import { getRelativePosition, fromRelativePosition } from '../Util/relativePosition.js'
+import Binding from '../Binding.js'
+import simpleDiff from '../../Util/simpleDiff.js'
+import { getRelativePosition, fromRelativePosition } from '../../Util/relativePosition.js'
function typeObserver () {
this._mutualExclude(() => {
diff --git a/src/Types/YArray/YArray.js b/src/Types/YArray/YArray.js
index 80033781..a901a89b 100644
--- a/src/Types/YArray/YArray.js
+++ b/src/Types/YArray/YArray.js
@@ -302,6 +302,7 @@ export default class YArray extends Type {
}
}
})
+ return content
}
/**
diff --git a/src/Types/YXml/YXmlElement.js b/src/Types/YXml/YXmlElement.js
index dfccdf1a..382396aa 100644
--- a/src/Types/YXml/YXmlElement.js
+++ b/src/Types/YXml/YXmlElement.js
@@ -1,7 +1,6 @@
-import { defaultDomFilter } from './utils.js'
-
import YMap from '../YMap/YMap.js'
import { YXmlFragment } from './YXml.js'
+import { createAssociation } from '../../Bindings/DomBinding/util.js'
/**
* An YXmlElement imitates the behavior of a
@@ -10,25 +9,12 @@ import { YXmlFragment } from './YXml.js'
* * An YXmlElement has attributes (key value pairs)
* * An YXmlElement has childElements that must inherit from YXmlElement
*
- * @param {String} arg1 Node name
- * @param {Function} arg2 Dom filter
+ * @param {String} nodeName Node name
*/
export default class YXmlElement extends YXmlFragment {
- constructor (arg1, arg2, _document) {
+ constructor (nodeName = 'UNDEFINED') {
super()
- this.nodeName = null
- this._scrollElement = null
- if (typeof arg1 === 'string') {
- this.nodeName = arg1.toUpperCase()
- } else if (arg1 != null && arg1.nodeType != null && arg1.nodeType === arg1.ELEMENT_NODE) {
- this.nodeName = arg1.nodeName
- this._setDom(arg1, _document)
- } else {
- this.nodeName = 'UNDEFINED'
- }
- if (typeof arg2 === 'function') {
- this._domFilter = arg2
- }
+ this.nodeName = nodeName.toUpperCase()
}
/**
@@ -41,48 +27,6 @@ export default class YXmlElement extends YXmlFragment {
return struct
}
- /**
- * @private
- * Copies children and attributes from a dom node to this YXmlElement.
- */
- _setDom (dom, _document) {
- if (this._dom != null) {
- throw new Error('Only call this method if you know what you are doing ;)')
- } else if (dom._yxml != null) { // TODO do i need to check this? - no.. but for dev purps..
- throw new Error('Already bound to an YXml type')
- } else {
- // tag is already set in constructor
- // set attributes
- let attributes = new Map()
- for (let i = 0; i < dom.attributes.length; i++) {
- let attr = dom.attributes[i]
- // get attribute via getAttribute for custom element support (some write something different in attr.value)
- attributes.set(attr.name, dom.getAttribute(attr.name))
- }
- attributes = this._domFilter(dom, attributes)
- attributes.forEach((value, name) => {
- this.setAttribute(name, value)
- })
- this.insertDomElements(0, Array.prototype.slice.call(dom.childNodes), _document)
- this._bindToDom(dom, _document)
- return dom
- }
- }
-
- /**
- * @private
- * Bind a dom to to this YXmlElement. This means that the DOM changes when the
- * YXmlElement is modified and that this YXmlElement changes when the DOM is
- * modified.
- *
- * Currently only works in YXmlFragment.
- */
- _bindToDom (dom, _document) {
- _document = _document || document
- this._dom = dom
- dom._yxml = this
- }
-
/**
* @private
* Read the next Item in a Decoder and fill this Item with the read data.
@@ -127,9 +71,6 @@ export default class YXmlElement extends YXmlFragment {
if (this.nodeName === null) {
throw new Error('nodeName must be defined!')
}
- if (this._domFilter === defaultDomFilter && this._parent._domFilter !== undefined) {
- this._domFilter = this._parent._domFilter
- }
super._integrate(y)
}
@@ -206,21 +147,16 @@ export default class YXmlElement extends YXmlFragment {
*
* @return {Element} The {@link https://developer.mozilla.org/en-US/docs/Web/API/Element|Dom Element}
*/
- getDom (_document) {
- _document = _document || document
- let dom = this._dom
- if (dom == null) {
- dom = _document.createElement(this.nodeName)
- dom._yxml = this
- let attrs = this.getAttributes()
- for (let key in attrs) {
- dom.setAttribute(key, attrs[key])
- }
- this.forEach(yxml => {
- dom.appendChild(yxml.getDom(_document))
- })
- this._bindToDom(dom, _document)
+ toDom (_document = document, binding) {
+ const dom = _document.createElement(this.nodeName)
+ let attrs = this.getAttributes()
+ for (let key in attrs) {
+ dom.setAttribute(key, attrs[key])
}
+ this.forEach(yxml => {
+ dom.appendChild(yxml.toDom(_document, binding))
+ })
+ createAssociation(binding, dom, this)
return dom
}
}
diff --git a/src/Types/YXml/YXmlEvent.js b/src/Types/YXml/YXmlEvent.js
index b27eb139..1fd884f4 100644
--- a/src/Types/YXml/YXmlEvent.js
+++ b/src/Types/YXml/YXmlEvent.js
@@ -4,8 +4,9 @@ import YEvent from '../../Util/YEvent.js'
* An Event that describes changes on a YXml Element or Yxml Fragment
*/
export default class YXmlEvent extends YEvent {
- constructor (target, subs, remote) {
+ constructor (target, subs, remote, transaction) {
super(target)
+ this._transaction = transaction
this.childListChanged = false
this.attributesChanged = new Set()
this.remote = remote
diff --git a/src/Types/YXml/YXmlFragment.js b/src/Types/YXml/YXmlFragment.js
index 5f98042c..6661fdd7 100644
--- a/src/Types/YXml/YXmlFragment.js
+++ b/src/Types/YXml/YXmlFragment.js
@@ -1,7 +1,7 @@
/* global MutationObserver */
-import { defaultDomFilter, applyChangesFromDom, reflectChangesOnDom } from './utils.js'
-import { beforeTransactionSelectionFixer, afterTransactionSelectionFixer } from './selection.js'
+import { createAssociation } from '../../Bindings/DomBinding/util.js'
+import YXmlTreeWalker from './YXmlTreeWalker.js'
import YArray from '../YArray/YArray.js'
import YXmlEvent from './YXmlEvent.js'
@@ -9,33 +9,6 @@ import { YXmlText, YXmlHook } from './YXml.js'
import { logID } from '../../MessageHandler/messageToString.js'
import diff from '../../Util/simpleDiff.js'
-function domToYXml (parent, doms, _document) {
- const types = []
- doms.forEach(d => {
- if (d._yxml != null && d._yxml !== false) {
- d._yxml._unbindFromDom()
- }
- if (parent._domFilter(d.nodeName, new Map()) !== null) {
- let type
- const hookName = d._yjsHook || (d.dataset != null ? d.dataset.yjsHook : undefined)
- if (hookName !== undefined) {
- type = new YXmlHook(hookName, d)
- } else if (d.nodeType === d.TEXT_NODE) {
- type = new YXmlText(d)
- } else if (d.nodeType === d.ELEMENT_NODE) {
- type = new YXmlFragment._YXmlElement(d, parent._domFilter, _document)
- } else {
- throw new Error('Unsupported node!')
- }
- // type.enableSmartScrolling(parent._scrollElement)
- types.push(type)
- } else {
- d._yxml = false
- }
- })
- return types
-}
-
/**
* Define the elements to which a set of CSS queries apply.
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors|CSS_Selectors}
@@ -48,64 +21,6 @@ function domToYXml (parent, doms, _document) {
* @typedef {string} CSS_Selector
*/
-/**
- * Represents a subset of the nodes of a YXmlElement / YXmlFragment and a
- * position within them.
- *
- * Can be created with {@link YXmlFragment#createTreeWalker}
- */
-class YXmlTreeWalker {
- constructor (root, f) {
- this._filter = f || (() => true)
- this._root = root
- this._currentNode = root
- this._firstCall = true
- }
- [Symbol.iterator] () {
- return this
- }
- /**
- * Get the next node.
- *
- * @return {YXmlElement} The next node.
- */
- next () {
- let n = this._currentNode
- if (this._firstCall) {
- this._firstCall = false
- if (!n._deleted && this._filter(n)) {
- return { value: n, done: false }
- }
- }
- do {
- if (!n._deleted && (n.constructor === YXmlFragment._YXmlElement || n.constructor === YXmlFragment) && n._start !== null) {
- // walk down in the tree
- n = n._start
- } else {
- // walk right or up in the tree
- while (n !== this._root) {
- if (n._right !== null) {
- n = n._right
- break
- }
- n = n._parent
- }
- if (n === this._root) {
- n = null
- }
- }
- if (n === this._root) {
- break
- }
- } while (n !== null && (n._deleted || !this._filter(n)))
- this._currentNode = n
- if (n === null) {
- return { done: true }
- } else {
- return { value: n, done: false }
- }
- }
-}
/**
* Represents a list of {@link YXmlElement}.
@@ -113,32 +28,6 @@ class YXmlTreeWalker {
* Therefore it also must not be added as a childElement.
*/
export default class YXmlFragment extends YArray {
- constructor () {
- super()
- this._dom = null
- this._domFilter = defaultDomFilter
- this._domObserver = null
- // this function makes sure that either the
- // dom event is executed, or the yjs observer is executed
- var token = true
- this._mutualExclude = f => {
- if (token) {
- token = false
- try {
- f()
- } catch (e) {
- console.error(e)
- }
- /*
- if (this._domObserver !== null) {
- this._domObserver.takeRecords()
- }
- */
- token = true
- }
- }
- }
-
/**
* Create a subtree of childNodes.
*
@@ -189,22 +78,6 @@ export default class YXmlFragment extends YArray {
return Array.from(new YXmlTreeWalker(this, element => element.nodeName === query))
}
- /**
- * Enables the smart scrolling functionality for a Dom Binding.
- * This is useful when YXml is bound to a shared editor. When activated,
- * the viewport will be changed to accommodate remote changes.
- *
- * @TODO: Disabled for now.
- *
- * @param {Element} scrollElement The node that is
- */
- enableSmartScrolling (scrollElement) {
- this._scrollElement = scrollElement
- this.forEach(xml => {
- xml.enableSmartScrolling(scrollElement)
- })
- }
-
/**
* Dom filter function.
*
@@ -214,44 +87,12 @@ export default class YXmlFragment extends YArray {
* @return {boolean} Whether to include the Dom node in the YXmlElement.
*/
- /**
- * Filter out Dom elements.
- *
- * @param {domFilter} f The filtering function that decides whether to include
- * a Dom node.
- */
- setDomFilter (f) {
- this._domFilter = f
- let attributes = new Map()
- if (this.getAttributes !== undefined) {
- let attrs = this.getAttributes()
- for (let key in attrs) {
- attributes.set(key, attrs[key])
- }
- }
- this._y.transact(() => {
- let result = this._domFilter(this.nodeName, new Map(attributes))
- if (result === null) {
- this._delete(this._y)
- } else {
- attributes.forEach((value, key) => {
- if (!result.has(key)) {
- this.removeAttribute(key)
- }
- })
- }
- this.forEach(xml => {
- xml.setDomFilter(f)
- })
- })
- }
-
/**
* @private
* Creates YArray Event and calls observers.
*/
_callObserver (transaction, parentSubs, remote) {
- this._callEventHandler(transaction, new YXmlEvent(this, parentSubs, remote))
+ this._callEventHandler(transaction, new YXmlEvent(this, parentSubs, remote, transaction))
}
/**
@@ -272,119 +113,20 @@ export default class YXmlFragment extends YArray {
* Type was deleted.
*/
_delete (y, createDelete) {
- this._unbindFromDom()
super._delete(y, createDelete)
}
/**
- * @private
- * Unbind this YXmlFragment from the Dom.
+ * @return {DocumentFragment} The dom representation of this
*/
- _unbindFromDom () {
- if (this._domObserver != null) {
- this._domObserver.disconnect()
- this._domObserver = null
- }
- if (this._dom != null) {
- this._dom._yxml = null
- this._dom = null
- }
- if (this._beforeTransactionHandler !== undefined) {
- this._y.off('beforeTransaction', this._beforeTransactionHandler)
- }
- }
-
- /**
- * Insert Dom Elements after one of the children of this YXmlFragment.
- * The Dom elements will be bound to a new YXmlElement and inserted at the
- * specified position.
- *
- * @param {YXmlElement|null} prev The reference node. New YxmlElements are
- * inserted after this node. Set null to insert at
- * the beginning.
- * @param {Array} doms The Dom elements to insert.
- * @param {?Document} _document Optional. Provide the global document object.
- * @return {Array} The YxmlElements that are inserted.
- */
- insertDomElementsAfter (prev, doms, _document) {
- const types = domToYXml(this, doms, _document)
- this.insertAfter(prev, types)
- return types
- }
-
- /**
- * Insert Dom Elements at a specified index.
- * The Dom elements will be bound to a new YXmlElement and inserted at the
- * specified position.
- *
- * @param {Integer} index The position to insert elements at.
- * @param {Array} doms The Dom elements to insert.
- * @param {?Document} _document Optional. Provide the global document object.
- * @return {Array} The YxmlElements that are inserted.
- */
- insertDomElements (index, doms, _document) {
- const types = domToYXml(this, doms, _document)
- this.insert(index, types)
- return types
- }
-
- /**
- * Get the Dom representation of this YXml type..
- */
- getDom () {
- return this._dom
- }
-
- /**
- * Bind this YXmlFragment and all its children to a Dom Element.
- * The content of the Dom Element are replaced with the Dom representation of
- * the children of this YXml Type.
- *
- * @param {Element} dom The Dom Element that should be bound to this Type.
- * @param {?Document} _document Optional. Provide the global document object.
- */
- bindToDom (dom, _document) {
- if (this._dom != null) {
- this._unbindFromDom()
- }
- if (dom._yxml != null) {
- dom._yxml._unbindFromDom()
- }
- dom.innerHTML = ''
- this.forEach(t => {
- dom.insertBefore(t.getDom(_document), null)
+ toDom (_document = document, binding) {
+ const fragment = _document.createDocumentFragment()
+ createAssociation(binding, fragment, this)
+ this.forEach(xmlType => {
+ fragment.insertBefore(xmlType.toDom(_document, binding), null)
})
- this._bindToDom(dom, _document)
+ return fragment
}
-
- /**
- * @private
- * Binds to a dom element.
- * Only call if dom and YXml are isomorph
- */
- _bindToDom (dom, _document) {
- _document = _document || document
- this._dom = dom
- dom._yxml = this
- if (this._parent === null) {
- return
- }
- this._y.on('beforeTransaction', beforeTransactionSelectionFixer)
- this._y.on('afterTransaction', afterTransactionSelectionFixer)
-
- this._y.on('beforeObserverCalls', function (y, transaction) {
- // apply dom filter to new and changed types
- transaction.changedTypes.forEach(function (subs, type) {
- if (subs.size > 1 || !subs.has(null)) {
- // only apply changes on attributes
- applyFilter(type)
- }
- })
- transaction.newTypes.forEach(applyFilter)
- })
- return dom
- }
-
/**
* @private
* Transform this YXml Type to a readable format.
diff --git a/src/Types/YXml/YXmlHook.js b/src/Types/YXml/YXmlHook.js
index b492ab2d..f0fb0f52 100644
--- a/src/Types/YXml/YXmlHook.js
+++ b/src/Types/YXml/YXmlHook.js
@@ -7,16 +7,12 @@ import { getHook, addHook } from './hooks.js'
* @param {String} hookName nodeName of the Dom Node.
*/
export default class YXmlHook extends YMap {
- constructor (hookName, dom) {
+ constructor (hookName) {
super()
- this._dom = null
this.hookName = null
if (hookName !== undefined) {
this.hookName = hookName
- this._dom = dom
dom._yjsHook = hookName
- dom._yxml = this
- getHook(hookName).fillType(dom, this)
}
}
@@ -31,27 +27,14 @@ export default class YXmlHook extends YMap {
}
/**
- * Returns the Dom representation of this YXmlHook.
+ * Creates a DOM element that represents this YXmlHook.
+ *
+ * @return Element The DOM representation of this Type.
*/
- getDom (_document) {
- _document = _document || document
- if (this._dom === null) {
- const dom = getHook(this.hookName).createDom(this)
- this._dom = dom
- dom._yxml = this
- dom._yjsHook = this.hookName
- }
- return this._dom
- }
-
- /**
- * @private
- * Removes the Dom binding.
- */
- _unbindFromDom () {
- this._dom._yxml = null
- this._yxml = null
- // TODO: cleanup hook?
+ toDom (_document = document) {
+ const dom = getHook(this.hookName).createDom(this)
+ dom._yjsHook = this.hookName
+ return dom
}
/**
@@ -99,11 +82,5 @@ export default class YXmlHook extends YMap {
}
super._integrate(y)
}
- setDomFilter () {
- // TODO: implement new modfilter method!
- }
- enableSmartScrolling () {
- // TODO: implement new smartscrolling method!
- }
}
YXmlHook.addHook = addHook
diff --git a/src/Types/YXml/YXmlText.js b/src/Types/YXml/YXmlText.js
index 1320a350..19013356 100644
--- a/src/Types/YXml/YXmlText.js
+++ b/src/Types/YXml/YXmlText.js
@@ -1,4 +1,5 @@
import YText from '../YText/YText.js'
+import { createAssociation } from '../../Bindings/DomBinding/util.js'
/**
* Represents text in a Dom Element. In the future this type will also handle
@@ -7,93 +8,16 @@ import YText from '../YText/YText.js'
* @param {String} arg1 Initial value.
*/
export default class YXmlText extends YText {
- constructor (arg1) {
- let dom = null
- let initialText = null
- if (arg1 != null) {
- if (arg1.nodeType != null && arg1.nodeType === arg1.TEXT_NODE) {
- dom = arg1
- initialText = dom.nodeValue
- } else if (typeof arg1 === 'string') {
- initialText = arg1
- }
- }
- super(initialText)
- this._dom = null
- this._domObserver = null
- this._domObserverListener = null
- this._scrollElement = null
- if (dom !== null) {
- this._setDom(arg1)
- }
- /*
- var token = true
- this._mutualExclude = f => {
- if (token) {
- token = false
- try {
- f()
- } catch (e) {
- console.error(e)
- }
- this._domObserver.takeRecords()
- token = true
- }
- }
- this.observe(event => {
- if (this._dom != null) {
- const dom = this._dom
- this._mutualExclude(() => {
- let anchorViewPosition = getAnchorViewPosition(this._scrollElement)
- let anchorViewFix
- if (anchorViewPosition !== null && (anchorViewPosition.anchor !== null || getBoundingClientRect(this._dom).top <= 0)) {
- anchorViewFix = anchorViewPosition
- } else {
- anchorViewFix = null
- }
- dom.nodeValue = this.toString()
- fixScrollPosition(this._scrollElement, anchorViewFix)
- })
- }
- })
- */
- }
- setDomFilter () {}
- enableSmartScrolling (scrollElement) {
- this._scrollElement = scrollElement
- }
/**
- * @private
- * Set Dom element / Text Node that represents the same content as this
- * YXmlElement.
+ * Creates a TextNode with the same textual content.
*
- * @param {Element} dom The Dom Element / Text Node that is set to be
- * equivalent to this Type.
+ * @return TextNode
*/
- _setDom (dom) {
- if (this._dom != null) {
- this._unbindFromDom()
- }
- if (dom._yxml != null) {
- dom._yxml._unbindFromDom()
- }
- // set marker
- this._dom = dom
- dom._yxml = this
- }
-
- /**
- * Returns the Dom representation of this YXmlText.
- */
- getDom (_document) {
- _document = _document || document
- if (this._dom === null) {
- const dom = _document.createTextNode(this.toString())
- this._setDom(dom)
- return dom
- }
- return this._dom
+ toDom (_document = document, binding) {
+ const dom = _document.createTextNode(this.toString())
+ createAssociation(binding, dom, this)
+ return dom
}
/**
@@ -105,22 +29,6 @@ export default class YXmlText extends YText {
* Type was deleted.
*/
_delete (y, createDelete) {
- this._unbindFromDom()
super._delete(y, createDelete)
}
-
- /**
- * @private
- * Unbind this YXmlText from the Dom.
- */
- _unbindFromDom () {
- if (this._domObserver != null) {
- this._domObserver.disconnect()
- this._domObserver = null
- }
- if (this._dom != null) {
- this._dom._yxml = null
- this._dom = null
- }
- }
}
diff --git a/src/Types/YXml/domFilter.js b/src/Types/YXml/domFilter.js
deleted file mode 100644
index ed992c53..00000000
--- a/src/Types/YXml/domFilter.js
+++ /dev/null
@@ -1,51 +0,0 @@
-
-const filterMap = new Map()
-
-export function addFilter (type, filter) {
- if (!filterMap.has(type)) {
- filterMap.set(type, new Set())
- }
- const filters = filterMap.get(type)
- filters.add(filter)
-}
-
-export function executeFilter (type) {
- const y = type._y
- let parent = type
- const nodeName = type.nodeName
- let attributes = new Map()
- if (type.getAttributes !== undefined) {
- let attrs = type.getAttributes()
- for (let key in attrs) {
- attributes.set(key, attrs[key])
- }
- }
- let filteredAttributes = new Map(attributes)
- // is not y, supports dom filtering
- while (parent !== y && parent.setDomFilter != null) {
- const filters = filterMap.get(parent)
- if (filters !== undefined) {
- for (let f of filters) {
- filteredAttributes = f(nodeName, filteredAttributes)
- if (filteredAttributes === null) {
- break
- }
- }
- if (filteredAttributes === null) {
- break
- }
- }
- parent = parent._parent
- }
- if (filteredAttributes === null) {
- type._delete(y)
- } else {
- // iterate original attributes
- attributes.forEach((value, key) => {
- // delete all attributes that are not in filteredAttributes
- if (!filteredAttributes.has(key)) {
- type.removeAttribute(key)
- }
- })
- }
-}
diff --git a/src/Types/YXml/utils.js b/src/Types/YXml/utils.js
deleted file mode 100644
index f405d8a3..00000000
--- a/src/Types/YXml/utils.js
+++ /dev/null
@@ -1,189 +0,0 @@
-import { YXmlText, YXmlHook } from './YXml.js'
-
-export function defaultDomFilter (node, attributes) {
- return attributes
-}
-
-export function getAnchorViewPosition (scrollElement) {
- if (scrollElement == null) {
- return null
- }
- let anchor = document.getSelection().anchorNode
- if (anchor != null) {
- let top = getBoundingClientRect(anchor).top
- if (top >= 0 && top <= document.documentElement.clientHeight) {
- return {
- anchor: anchor,
- top: top
- }
- }
- }
- return {
- anchor: null,
- scrollTop: scrollElement.scrollTop,
- scrollHeight: scrollElement.scrollHeight
- }
-}
-
-// get BoundingClientRect that works on text nodes
-export function getBoundingClientRect (element) {
- if (element.getBoundingClientRect != null) {
- // is element node
- return element.getBoundingClientRect()
- } else {
- // is text node
- if (element.parentNode == null) {
- // range requires that text nodes have a parent
- let span = document.createElement('span')
- span.appendChild(element)
- }
- let range = document.createRange()
- range.selectNode(element)
- return range.getBoundingClientRect()
- }
-}
-
-export function fixScrollPosition (scrollElement, fix) {
- if (scrollElement !== null && fix !== null) {
- if (fix.anchor === null) {
- if (scrollElement.scrollTop === fix.scrollTop) {
- scrollElement.scrollTop = scrollElement.scrollHeight - fix.scrollHeight
- }
- } else {
- scrollElement.scrollTop = getBoundingClientRect(fix.anchor).top - fix.top
- }
- }
-}
-
-
-export function reflectChangesOnDom (events, _document) {
- // Make sure that no filtered attributes are applied to the structure
- // if they were, delete them
- /*
- events.forEach(event => {
- const target = event.target
- if (event.attributesChanged === undefined) {
- // event.target is Y.XmlText
- return
- }
- const keys = this._domFilter(target.nodeName, Array.from(event.attributesChanged))
- if (keys === null) {
- target._delete()
- } else {
- const removeKeys = new Set() // is a copy of event.attributesChanged
- event.attributesChanged.forEach(key => { removeKeys.add(key) })
- keys.forEach(key => {
- // remove all accepted keys from removeKeys
- removeKeys.delete(key)
- })
- // remove the filtered attribute
- removeKeys.forEach(key => {
- target.removeAttribute(key)
- })
- }
- })
- */
- this._mutualExclude(() => {
- events.forEach(event => {
- const yxml = event.target
- const dom = yxml._dom
- if (dom != null) {
- // TODO: do this once before applying stuff
- // let anchorViewPosition = getAnchorViewPosition(yxml._scrollElement)
- if (yxml.constructor === YXmlText) {
- yxml._dom.nodeValue = yxml.toString()
- } else if (event.attributesChanged !== undefined) {
- // update attributes
- event.attributesChanged.forEach(attributeName => {
- const value = yxml.getAttribute(attributeName)
- if (value === undefined) {
- dom.removeAttribute(attributeName)
- } else {
- dom.setAttribute(attributeName, value)
- }
- })
- /*
- * TODO: instead of hard-checking the types, it would be best to
- * specify the type's features. E.g.
- * - _yxmlHasAttributes
- * - _yxmlHasChildren
- * Furthermore, the features shouldn't be encoded in the types,
- * only in the attributes (above)
- */
- if (event.childListChanged && yxml.constructor !== YXmlHook) {
- let currentChild = dom.firstChild
- yxml.forEach(function (t) {
- let expectedChild = t.getDom(_document)
- if (expectedChild.parentNode === dom) {
- // is already attached to the dom. Look for it
- while (currentChild !== expectedChild) {
- let del = currentChild
- currentChild = currentChild.nextSibling
- dom.removeChild(del)
- }
- currentChild = currentChild.nextSibling
- } else {
- // this dom is not yet attached to dom
- dom.insertBefore(expectedChild, currentChild)
- }
- })
- while (currentChild !== null) {
- let tmp = currentChild.nextSibling
- dom.removeChild(currentChild)
- currentChild = tmp
- }
- }
- }
- /* TODO: smartscrolling
- .. else if (event.type === 'childInserted' || event.type === 'insert') {
- let nodes = event.values
- for (let i = nodes.length - 1; i >= 0; i--) {
- let node = nodes[i]
- node.setDomFilter(yxml._domFilter)
- node.enableSmartScrolling(yxml._scrollElement)
- let dom = node.getDom()
- let fixPosition = null
- let nextDom = null
- if (yxml._content.length > event.index + i + 1) {
- nextDom = yxml.get(event.index + i + 1).getDom()
- }
- yxml._dom.insertBefore(dom, nextDom)
- if (anchorViewPosition === null) {
- // nop
- } else if (anchorViewPosition.anchor !== null) {
- // no scrolling when current selection
- if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) {
- fixPosition = anchorViewPosition
- }
- } else if (getBoundingClientRect(dom).top <= 0) {
- // adjust scrolling if modified element is out of view,
- // there is no anchor element, and the browser did not adjust scrollTop (this is checked later)
- fixPosition = anchorViewPosition
- }
- fixScrollPosition(yxml._scrollElement, fixPosition)
- }
- } else if (event.type === 'childRemoved' || event.type === 'delete') {
- for (let i = event.values.length - 1; i >= 0; i--) {
- let dom = event.values[i]._dom
- let fixPosition = null
- if (anchorViewPosition === null) {
- // nop
- } else if (anchorViewPosition.anchor !== null) {
- // no scrolling when current selection
- if (!dom.contains(anchorViewPosition.anchor) && !anchorViewPosition.anchor.contains(dom)) {
- fixPosition = anchorViewPosition
- }
- } else if (getBoundingClientRect(dom).top <= 0) {
- // adjust scrolling if modified element is out of view,
- // there is no anchor element, and the browser did not adjust scrollTop (this is checked later)
- fixPosition = anchorViewPosition
- }
- dom.remove()
- fixScrollPosition(yxml._scrollElement, fixPosition)
- }
- }
- */
- }
- })
- })
-}
diff --git a/src/Util/isParentOf.js b/src/Util/isParentOf.js
new file mode 100644
index 00000000..76c3deab
--- /dev/null
+++ b/src/Util/isParentOf.js
@@ -0,0 +1,18 @@
+
+/**
+ * Check if `parent` is a parent of `child`.
+ *
+ * @param {Type} parent
+ * @param {Type} child
+ * @return {Boolean} Whether `parent` is a parent of `child`.
+ */
+export default function isParentOf (parent, child) {
+ child = child._parent
+ while (child !== null) {
+ if (child === parent) {
+ return true
+ }
+ child = child._parent
+ }
+ return false
+}
diff --git a/src/Y.dist.js b/src/Y.dist.js
index e8d63022..92df64c7 100644
--- a/src/Y.dist.js
+++ b/src/Y.dist.js
@@ -14,8 +14,9 @@ import { YXmlFragment, YXmlElement, YXmlText, YXmlHook } from './Types/YXml/YXml
import BinaryDecoder from './Util/Binary/Decoder.js'
import { getRelativePosition, fromRelativePosition } from './Util/relativePosition.js'
import { registerStruct } from './Util/structReferences.js'
-import TextareaBinding from './Bindings/TextareaBinding.js'
-import QuillBinding from './Bindings/QuillBinding.js'
+import TextareaBinding from './Bindings/TextareaBinding/TextareaBinding.js'
+import QuillBinding from './Bindings/QuillBinding/QuillBinding.js'
+import DomBinding from './Bindings/DomBinding/DomBinding.js'
import { toBinary, fromBinary } from './MessageHandler/binaryEncode.js'
import debug from 'debug'
@@ -33,6 +34,7 @@ Y.XmlHook = YXmlHook
Y.TextareaBinding = TextareaBinding
Y.QuillBinding = QuillBinding
+Y.DomBinding = DomBinding
Y.utils = {
BinaryDecoder,
diff --git a/src/Y.js b/src/Y.js
index e06dc940..ae81f937 100644
--- a/src/Y.js
+++ b/src/Y.js
@@ -6,6 +6,8 @@ import RootID from './Util/ID/RootID.js'
import NamedEventHandler from './Util/NamedEventHandler.js'
import Transaction from './Transaction.js'
+export { default as DomBinding } from './Bindings/DomBinding/DomBinding.js'
+
/**
* A positive natural number including zero: 0, 1, 2, ..
*
@@ -44,7 +46,11 @@ export default class Y extends NamedEventHandler {
}
this._contentReady = false
this._opts = opts
- this.userID = generateUserID()
+ if (typeof opts.userID !== 'number') {
+ this.userID = generateUserID()
+ } else {
+ this.userID = opts.userID
+ }
// TODO: This should be a Map so we can use encodables as keys
this.share = {}
this.ds = new DeleteStore(this)
@@ -77,6 +83,8 @@ export default class Y extends NamedEventHandler {
} else {
initConnection()
}
+ // for compatibility with isParentOf
+ this._parent = null
}
_setContentReady () {
if (!this._contentReady) {
diff --git a/test/y-xml.tests.js b/test/y-xml.tests.js
index efe8d949..d168691c 100644
--- a/test/y-xml.tests.js
+++ b/test/y-xml.tests.js
@@ -3,14 +3,13 @@ import { test } from 'cutest'
test('set property', async function xml0 (t) {
var { users, xml0, xml1 } = await initArrays(t, { users: 2 })
- xml0.setAttribute('height', 10)
- t.assert(xml0.getAttribute('height') === 10, 'Simple set+get works')
+ xml0.setAttribute('height', '10')
+ t.assert(xml0.getAttribute('height') === '10', 'Simple set+get works')
await flushAll(t, users)
- t.assert(xml1.getAttribute('height') === 10, 'Simple set+get works (remote)')
+ t.assert(xml1.getAttribute('height') === '10', 'Simple set+get works (remote)')
await compareUsers(t, users)
})
-/* TODO: Test YXml events!
test('events', async function xml1 (t) {
var { users, xml0, xml1 } = await initArrays(t, { users: 2 })
var event
@@ -29,48 +28,28 @@ test('events', async function xml1 (t) {
remoteEvent = e
})
xml0.setAttribute('key', 'value')
- expectedEvent = {
- type: 'attributeChanged',
- value: 'value',
- name: 'key'
- }
- t.compare(event, expectedEvent, 'attribute changed event')
+ t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key')
await flushAll(t, users)
- t.compare(remoteEvent, expectedEvent, 'attribute changed event (remote)')
+ t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on updated key (remote)')
// check attributeRemoved
xml0.removeAttribute('key')
- expectedEvent = {
- type: 'attributeRemoved',
- name: 'key'
- }
- t.compare(event, expectedEvent, 'attribute deleted event')
+ t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute')
await flushAll(t, users)
- t.compare(remoteEvent, expectedEvent, 'attribute deleted event (remote)')
- // test childInserted event
- expectedEvent = {
- type: 'childInserted',
- index: 0
- }
+ t.assert(event.attributesChanged.has('key'), 'YXmlEvent.attributesChanged on removed attribute (remote)')
xml0.insert(0, [new Y.XmlText('some text')])
- t.compare(event, expectedEvent, 'child inserted event')
+ t.assert(event.childListChanged, 'YXmlEvent.childListChanged on inserted element')
await flushAll(t, users)
- t.compare(remoteEvent, expectedEvent, 'child inserted event (remote)')
+ t.assert(event.childListChanged, 'YXmlEvent.childListChanged on inserted element (remote)')
// test childRemoved
xml0.delete(0)
- expectedEvent = {
- type: 'childRemoved',
- index: 0
- }
- t.compare(event, expectedEvent, 'child deleted event')
+ t.assert(event.childListChanged, 'YXmlEvent.childListChanged on deleted element')
await flushAll(t, users)
- t.compare(remoteEvent, expectedEvent, 'child deleted event (remote)')
+ t.assert(event.childListChanged, 'YXmlEvent.childListChanged on deleted element (remote)')
await compareUsers(t, users)
})
-*/
test('attribute modifications (y -> dom)', async function xml2 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.setAttribute('height', '100px')
await wait()
t.assert(dom0.getAttribute('height') === '100px', 'setAttribute')
@@ -84,8 +63,7 @@ test('attribute modifications (y -> dom)', async function xml2 (t) {
})
test('attribute modifications (dom -> y)', async function xml3 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
dom0.setAttribute('height', '100px')
await wait()
t.assert(xml0.getAttribute('height') === '100px', 'setAttribute')
@@ -99,8 +77,7 @@ test('attribute modifications (dom -> y)', async function xml3 (t) {
})
test('element insert (dom -> y)', async function xml4 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
dom0.insertBefore(document.createTextNode('some text'), null)
dom0.insertBefore(document.createElement('p'), null)
await wait()
@@ -110,8 +87,7 @@ test('element insert (dom -> y)', async function xml4 (t) {
})
test('element insert (y -> dom)', async function xml5 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.insert(0, [new Y.XmlText('some text')])
xml0.insert(1, [new Y.XmlElement('p')])
t.assert(dom0.childNodes[0].textContent === 'some text', 'Retrieve Text node')
@@ -120,8 +96,7 @@ test('element insert (y -> dom)', async function xml5 (t) {
})
test('y on insert, then delete (dom -> y)', async function xml6 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
dom0.insertBefore(document.createElement('p'), null)
await wait()
t.assert(xml0.length === 1, 'one node present')
@@ -132,8 +107,7 @@ test('y on insert, then delete (dom -> y)', async function xml6 (t) {
})
test('y on insert, then delete (y -> dom)', async function xml7 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.insert(0, [new Y.XmlElement('p')])
t.assert(dom0.childNodes[0].nodeName === 'P', 'Get inserted element from dom')
xml0.delete(0, 1)
@@ -142,8 +116,7 @@ test('y on insert, then delete (y -> dom)', async function xml7 (t) {
})
test('delete consecutive (1) (Text)', async function xml8 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.insert(0, [new Y.XmlText('1'), new Y.XmlText('2'), new Y.XmlText('3')])
await wait()
xml0.delete(1, 2)
@@ -155,8 +128,7 @@ test('delete consecutive (1) (Text)', async function xml8 (t) {
})
test('delete consecutive (2) (Text)', async function xml9 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.insert(0, [new Y.XmlText('1'), new Y.XmlText('2'), new Y.XmlText('3')])
await wait()
xml0.delete(0, 1)
@@ -169,8 +141,7 @@ test('delete consecutive (2) (Text)', async function xml9 (t) {
})
test('delete consecutive (1) (Element)', async function xml10 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.insert(0, [new Y.XmlElement('A'), new Y.XmlElement('B'), new Y.XmlElement('C')])
await wait()
xml0.delete(1, 2)
@@ -182,8 +153,7 @@ test('delete consecutive (1) (Element)', async function xml10 (t) {
})
test('delete consecutive (2) (Element)', async function xml11 (t) {
- var { users, xml0 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
+ var { users, xml0, dom0 } = await initArrays(t, { users: 3 })
xml0.insert(0, [new Y.XmlElement('A'), new Y.XmlElement('B'), new Y.XmlElement('C')])
await wait()
xml0.delete(0, 1)
@@ -196,9 +166,7 @@ test('delete consecutive (2) (Element)', async function xml11 (t) {
})
test('Receive a bunch of elements (with disconnect)', async function xml12 (t) {
- var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
- let dom1 = xml1.getDom()
+ var { users, xml0, xml1, dom0, dom1 } = await initArrays(t, { users: 3 })
users[1].disconnect()
xml0.insert(0, [new Y.XmlElement('A'), new Y.XmlElement('B'), new Y.XmlElement('C')])
xml0.insert(0, [new Y.XmlElement('X'), new Y.XmlElement('Y'), new Y.XmlElement('Z')])
@@ -212,9 +180,7 @@ test('Receive a bunch of elements (with disconnect)', async function xml12 (t) {
})
test('move element to a different position', async function xml13 (t) {
- var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
- let dom1 = xml1.getDom()
+ var { users, xml0, xml1, dom0, dom1 } = await initArrays(t, { users: 3 })
dom0.append(document.createElement('div'))
dom0.append(document.createElement('h1'))
await flushAll(t, users)
@@ -227,9 +193,7 @@ test('move element to a different position', async function xml13 (t) {
})
test('filter node', async function xml14 (t) {
- var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
- let dom1 = xml1.getDom()
+ var { users, xml0, xml1, dom0, dom1, domBinding0, domBinding1 } = await initArrays(t, { users: 3 })
let domFilter = (nodeName, attrs) => {
if (nodeName === 'H1') {
return null
@@ -237,8 +201,8 @@ test('filter node', async function xml14 (t) {
return attrs
}
}
- xml0.setDomFilter(domFilter)
- xml1.setDomFilter(domFilter)
+ domBinding0.setFilter(domFilter)
+ domBinding1.setFilter(domFilter)
dom0.append(document.createElement('div'))
dom0.append(document.createElement('h1'))
await flushAll(t, users)
@@ -248,15 +212,13 @@ test('filter node', async function xml14 (t) {
})
test('filter attribute', async function xml15 (t) {
- var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
- let dom1 = xml1.getDom()
+ var { users, xml0, xml1, dom0, dom1, domBinding0, domBinding1 } = await initArrays(t, { users: 3 })
let domFilter = (nodeName, attrs) => {
attrs.delete('hidden')
return attrs
}
- xml0.setDomFilter(domFilter)
- xml1.setDomFilter(domFilter)
+ domBinding0.setFilter(domFilter)
+ domBinding1.setFilter(domFilter)
dom0.setAttribute('hidden', 'true')
dom0.setAttribute('style', 'height: 30px')
dom0.setAttribute('data-me', '77')
@@ -269,9 +231,7 @@ test('filter attribute', async function xml15 (t) {
})
test('deep element insert', async function xml16 (t) {
- var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
- let dom0 = xml0.getDom()
- let dom1 = xml1.getDom()
+ var { users, xml0, xml1, dom0, dom1 } = await initArrays(t, { users: 3 })
let deepElement = document.createElement('p')
let boldElement = document.createElement('b')
let attrElement = document.createElement('img')
@@ -291,8 +251,8 @@ test('treeWalker', async function xml17 (t) {
var { users, xml0 } = await initArrays(t, { users: 3 })
let paragraph1 = new Y.XmlElement('p')
let paragraph2 = new Y.XmlElement('p')
- let text1 = new Y.Text('init')
- let text2 = new Y.Text('text')
+ let text1 = new Y.XmlText('init')
+ let text2 = new Y.XmlText('text')
paragraph1.insert(0, [text1, text2])
xml0.insert(0, [paragraph1, paragraph2, new Y.XmlElement('img')])
let allParagraphs = xml0.querySelectorAll('p')
@@ -309,8 +269,8 @@ test('treeWalker', async function xml17 (t) {
* Incoming changes that contain malicious attributes should be deleted.
*/
test('Filtering remote changes', async function xmlFilteringRemote (t) {
- var { users, xml0, xml1 } = await initArrays(t, { users: 3 })
- xml0.setDomFilter(function (nodeName, attributes) {
+ var { users, xml0, xml1, domBinding0 } = await initArrays(t, { users: 3 })
+ domBinding0.setFilter(function (nodeName, attributes) {
attributes.delete('malicious')
if (nodeName === 'HIDEME') {
return null
@@ -320,10 +280,6 @@ test('Filtering remote changes', async function xmlFilteringRemote (t) {
return attributes
}
})
- // make sure that dom filters are active
- // TODO: do not rely on .getDom for domFilters
- xml0.getDom()
- xml1.getDom()
let paragraph = new Y.XmlElement('p')
let hideMe = new Y.XmlElement('hideMe')
let span = new Y.XmlElement('span')
@@ -337,8 +293,8 @@ test('Filtering remote changes', async function xmlFilteringRemote (t) {
paragraph.insert(0, [tag2])
await flushAll(t, users)
// check dom
- paragraph.getDom().setAttribute('malicious', 'true')
- span.getDom().setAttribute('malicious', 'true')
+ domBinding0.typeToDom.get(paragraph).setAttribute('malicious', 'true')
+ domBinding0.typeToDom.get(span).setAttribute('malicious', 'true')
// check incoming attributes
xml1.get(0).get(0).setAttribute('malicious', 'true')
xml1.insert(0, [new Y.XmlElement('hideMe')])
@@ -350,35 +306,35 @@ test('Filtering remote changes', async function xmlFilteringRemote (t) {
// TODO: move elements
var xmlTransactions = [
function attributeChange (t, user, chance) {
- user.get('xml', Y.XmlElement).getDom().setAttribute(chance.word(), chance.word())
+ user.dom.setAttribute(chance.word(), chance.word())
},
function attributeChangeHidden (t, user, chance) {
- user.get('xml', Y.XmlElement).getDom().setAttribute('hidden', chance.word())
+ user.dom.setAttribute('hidden', chance.word())
},
function insertText (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
dom.insertBefore(document.createTextNode(chance.word()), succ)
},
function insertHiddenDom (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
dom.insertBefore(document.createElement('hidden'), succ)
},
function insertDom (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
var succ = dom.children.length > 0 ? chance.pickone(dom.children) : null
dom.insertBefore(document.createElement(chance.word()), succ)
},
function deleteChild (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
if (dom.childNodes.length > 0) {
var d = chance.pickone(dom.childNodes)
d.remove()
}
},
function insertTextSecondLayer (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
if (dom.children.length > 0) {
let dom2 = chance.pickone(dom.children)
let succ = dom2.childNodes.length > 0 ? chance.pickone(dom2.childNodes) : null
@@ -386,7 +342,7 @@ var xmlTransactions = [
}
},
function insertDomSecondLayer (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
if (dom.children.length > 0) {
let dom2 = chance.pickone(dom.children)
let succ = dom2.childNodes.length > 0 ? chance.pickone(dom2.childNodes) : null
@@ -394,7 +350,7 @@ var xmlTransactions = [
}
},
function deleteChildSecondLayer (t, user, chance) {
- let dom = user.get('xml', Y.XmlElement).getDom()
+ let dom = user.dom
if (dom.children.length > 0) {
let dom2 = chance.pickone(dom.children)
if (dom2.childNodes.length > 0) {
diff --git a/tests-lib/helper.js b/tests-lib/helper.js
index a760ab19..d4bf1ea4 100644
--- a/tests-lib/helper.js
+++ b/tests-lib/helper.js
@@ -1,6 +1,7 @@
-import _Y from '../src/Y.js'
-import yTest from './test-connector.js'
+import _Y from '../src/Y.dist.js'
+import { DomBinding } from '../src/Y.js'
+import TestConnector from './test-connector.js'
import Chance from 'chance'
import ItemJSON from '../src/Struct/ItemJSON.js'
@@ -10,11 +11,11 @@ import Quill from 'quill'
export const Y = _Y
-Y.extend(yTest)
-
export const database = { name: 'memory' }
export const connector = { name: 'test', url: 'http://localhost:1234' }
+Y.test = TestConnector
+
function getStateSet (y) {
let ss = {}
for (let [user, clock] of y.ss.state) {
@@ -40,6 +41,7 @@ function getDeleteSet (y) {
return ds
}
+// TODO: remove?
export function attrsObject (dom) {
let keys = []
let yxml = dom._yxml
@@ -55,6 +57,7 @@ export function attrsObject (dom) {
return obj
}
+// TODO: remove?
export function domToJson (dom) {
if (dom.nodeType === document.TEXT_NODE) {
return dom.textContent
@@ -140,6 +143,14 @@ export async function compareUsers (t, users) {
users.map(u => u.destroy())
}
+function domFilter (nodeName, attrs) {
+ if (nodeName === 'HIDDEN') {
+ return null
+ }
+ attrs.delete('hidden')
+ return attrs
+}
+
export async function initArrays (t, opts) {
var result = {
users: []
@@ -154,27 +165,25 @@ export async function initArrays (t, opts) {
connOpts = Object.assign({ role: 'slave' }, conn)
}
let y = new Y(connOpts.room, {
- _userID: i, // evil hackery, don't try this at home
+ userID: i, // evil hackery, don't try this at home
connector: connOpts
})
result.users.push(y)
result['array' + i] = y.define('array', Y.Array)
result['map' + i] = y.define('map', Y.Map)
- result['xml' + i] = y.define('xml', Y.XmlElement)
+ const yxml = y.define('xml', Y.XmlElement)
+ result['xml' + i] = yxml
+ const dom = document.createElement('my-dom')
+ const domBinding = new DomBinding(yxml, dom, { domFilter })
+ result['domBinding' + i] = domBinding
+ result['dom' + i] = dom
const textType = y.define('text', Y.Text)
result['text' + i] = textType
const quill = new Quill(document.createElement('div'))
- const quillBinding = new Y.QuillBinding(textType, quill)
+ result['quillBinding' + i] = new Y.QuillBinding(textType, quill)
result['quill' + i] = quill
- result['quillBinding' + i] = quillBinding
y.quill = quill // put quill on the y object (so we can use it later)
- y.get('xml').setDomFilter(function (nodeName, attrs) {
- if (nodeName === 'HIDDEN') {
- return null
- }
- attrs.delete('hidden')
- return attrs
- })
+ y.dom = dom
y.on('afterTransaction', function () {
for (let missing of y._missingStructs.values()) {
if (Array.from(missing.values()).length > 0) {
diff --git a/tests-lib/test-connector.js b/tests-lib/test-connector.js
index ec24f71d..8cb0fdb6 100644
--- a/tests-lib/test-connector.js
+++ b/tests-lib/test-connector.js
@@ -1,6 +1,7 @@
/* global Y */
import { wait } from './helper'
import { messageToString } from '../src/MessageHandler/messageToString'
+import AbstractConnector from '../src/Connector.js'
var rooms = {}
@@ -64,107 +65,99 @@ function getTestRoom (roomname) {
return rooms[roomname]
}
-export default function extendTestConnector (Y) {
- class TestConnector extends Y.AbstractConnector {
- constructor (y, options) {
- if (options === undefined) {
- throw new Error('Options must not be undefined!')
- }
- if (options.room == null) {
- throw new Error('You must define a room name!')
- }
- options.forwardAppliedOperations = options.role === 'master'
- super(y, options)
- this.options = options
- this.room = options.room
- this.chance = options.chance
- this.testRoom = getTestRoom(this.room)
- this.testRoom.join(this)
+export default class TestConnector extends AbstractConnector {
+ constructor (y, options) {
+ if (options === undefined) {
+ throw new Error('Options must not be undefined!')
}
- disconnect () {
- this.testRoom.leave(this)
- return super.disconnect()
+ if (options.room == null) {
+ throw new Error('You must define a room name!')
}
- logBufferParsed () {
- console.log(' === Logging buffer of user ' + this.y.userID + ' === ')
- for (let [user, conn] of this.connections) {
- console.log(` ${user}:`)
- for (let i = 0; i < conn.buffer.length; i++) {
- console.log(messageToString(conn.buffer[i]))
- }
+ options.forwardAppliedOperations = options.role === 'master'
+ super(y, options)
+ this.options = options
+ this.room = options.room
+ this.chance = options.chance
+ this.testRoom = getTestRoom(this.room)
+ this.testRoom.join(this)
+ }
+ disconnect () {
+ this.testRoom.leave(this)
+ return super.disconnect()
+ }
+ logBufferParsed () {
+ console.log(' === Logging buffer of user ' + this.y.userID + ' === ')
+ for (let [user, conn] of this.connections) {
+ console.log(` ${user}:`)
+ for (let i = 0; i < conn.buffer.length; i++) {
+ console.log(messageToString(conn.buffer[i]))
}
}
- reconnect () {
- this.testRoom.join(this)
- super.reconnect()
- return new Promise(resolve => {
- this.whenSynced(resolve)
- })
- }
- send (uid, message) {
- super.send(uid, message)
- this.testRoom.send(this.y.userID, uid, message)
- }
- broadcast (message) {
- super.broadcast(message)
- this.testRoom.broadcast(this.y.userID, message)
- }
- async whenSynced (f) {
- var synced = false
- var periodicFlushTillSync = () => {
- if (synced) {
- f()
- } else {
- this.testRoom.flushAll([this.y]).then(function () {
- setTimeout(periodicFlushTillSync, 10)
- })
- }
- }
- periodicFlushTillSync()
- return super.whenSynced(function () {
- synced = true
- })
- }
- receiveMessage (sender, m) {
- if (this.y.userID !== sender && this.connections.has(sender)) {
- var buffer = this.connections.get(sender).buffer
- if (buffer == null) {
- buffer = this.connections.get(sender).buffer = []
- }
- buffer.push(m)
- if (this.chance.bool({likelihood: 30})) {
- // flush 1/2 with 30% chance
- var flushLength = Math.round(buffer.length / 2)
- buffer.splice(0, flushLength).forEach(m => {
- super.receiveMessage(sender, m)
- })
- }
+ }
+ reconnect () {
+ this.testRoom.join(this)
+ super.reconnect()
+ return new Promise(resolve => {
+ this.whenSynced(resolve)
+ })
+ }
+ send (uid, message) {
+ super.send(uid, message)
+ this.testRoom.send(this.y.userID, uid, message)
+ }
+ broadcast (message) {
+ super.broadcast(message)
+ this.testRoom.broadcast(this.y.userID, message)
+ }
+ async whenSynced (f) {
+ var synced = false
+ var periodicFlushTillSync = () => {
+ if (synced) {
+ f()
+ } else {
+ this.testRoom.flushAll([this.y]).then(function () {
+ setTimeout(periodicFlushTillSync, 10)
+ })
}
}
- async _flushAll (flushUsers) {
- if (flushUsers.some(u => u.connector.y.userID === this.y.userID)) {
- // this one needs to sync with every other user
- flushUsers = Array.from(this.connections.keys()).map(uid => this.testRoom.users.get(uid).y)
+ periodicFlushTillSync()
+ return super.whenSynced(function () {
+ synced = true
+ })
+ }
+ receiveMessage (sender, m) {
+ if (this.y.userID !== sender && this.connections.has(sender)) {
+ var buffer = this.connections.get(sender).buffer
+ if (buffer == null) {
+ buffer = this.connections.get(sender).buffer = []
}
- for (let i = 0; i < flushUsers.length; i++) {
- let userID = flushUsers[i].connector.y.userID
- if (userID !== this.y.userID && this.connections.has(userID)) {
- let buffer = this.connections.get(userID).buffer
- if (buffer != null) {
- var messages = buffer.splice(0)
- for (let j = 0; j < messages.length; j++) {
- super.receiveMessage(userID, messages[j])
- }
+ buffer.push(m)
+ if (this.chance.bool({likelihood: 30})) {
+ // flush 1/2 with 30% chance
+ var flushLength = Math.round(buffer.length / 2)
+ buffer.splice(0, flushLength).forEach(m => {
+ super.receiveMessage(sender, m)
+ })
+ }
+ }
+ }
+ async _flushAll (flushUsers) {
+ if (flushUsers.some(u => u.connector.y.userID === this.y.userID)) {
+ // this one needs to sync with every other user
+ flushUsers = Array.from(this.connections.keys()).map(uid => this.testRoom.users.get(uid).y)
+ }
+ for (let i = 0; i < flushUsers.length; i++) {
+ let userID = flushUsers[i].connector.y.userID
+ if (userID !== this.y.userID && this.connections.has(userID)) {
+ let buffer = this.connections.get(userID).buffer
+ if (buffer != null) {
+ var messages = buffer.splice(0)
+ for (let j = 0; j < messages.length; j++) {
+ super.receiveMessage(userID, messages[j])
}
}
}
- return 'done'
}
+ return 'done'
}
- // TODO: this should be moved to a separate module (dont work on Y)
- Y.test = TestConnector
-}
-
-if (typeof Y !== 'undefined') {
- extendTestConnector(Y)
}