diff --git a/.prettierrc b/.prettierrc
index de3c347..94d339e 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,6 +1,5 @@
{
"printWidth": 140,
- "parser": "typescript",
"semi": true,
"tabWidth": 2,
"useTabs": false,
diff --git a/.travis.yml b/.travis.yml
index cff5a1d..9ac9f06 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,7 @@ language: node_js
dist: trusty
sudo: required
node_js:
-- '8'
+- '12'
before_install:
- npm install -g @angular/cli @angular/compiler-cli typescript
install: npm install
diff --git a/package-lock.json b/package-lock.json
index 09fbfec..968083b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -536,6 +536,453 @@
"path-exists": "^4.0.0"
}
},
+ "fsevents": {
+ "version": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
+ "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
+ "requires": {
+ "nan": "^2.12.1",
+ "node-pre-gyp": "^0.12.0"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": false,
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": false,
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "resolved": false,
+ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "resolved": false,
+ "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": false,
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": false,
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.1",
+ "resolved": false,
+ "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": false,
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "resolved": false,
+ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": false,
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "debug": {
+ "version": "4.1.1",
+ "resolved": false,
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": false,
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": false,
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "resolved": false,
+ "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
+ },
+ "fs-minipass": {
+ "version": "1.2.5",
+ "resolved": false,
+ "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": false,
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "resolved": false,
+ "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "resolved": false,
+ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "resolved": false,
+ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": false,
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "resolved": false,
+ "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": false,
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": false,
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": false,
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": false,
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": false,
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "resolved": false,
+ "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ },
+ "minipass": {
+ "version": "2.3.5",
+ "resolved": false,
+ "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "resolved": false,
+ "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "resolved": false,
+ "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": false,
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "needle": {
+ "version": "2.3.0",
+ "resolved": false,
+ "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
+ "requires": {
+ "debug": "^4.1.0",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.12.0",
+ "resolved": false,
+ "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "resolved": false,
+ "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.6",
+ "resolved": false,
+ "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g=="
+ },
+ "npm-packlist": {
+ "version": "1.4.1",
+ "resolved": false,
+ "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "resolved": false,
+ "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": false,
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": false,
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "resolved": false,
+ "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": false,
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "resolved": false,
+ "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": false,
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "resolved": false,
+ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+ },
+ "rc": {
+ "version": "1.2.8",
+ "resolved": false,
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": false,
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ }
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "resolved": false,
+ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": false,
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": false,
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": false,
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "sax": {
+ "version": "1.2.4",
+ "resolved": false,
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
+ "semver": {
+ "version": "5.7.0",
+ "resolved": false,
+ "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": false,
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": false,
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": false,
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": false,
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": false,
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
+ "tar": {
+ "version": "4.4.8",
+ "resolved": false,
+ "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.4",
+ "minizlib": "^1.1.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": false,
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "resolved": false,
+ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA=="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": false,
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "resolved": false,
+ "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
+ }
+ }
+ },
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -563,6 +1010,11 @@
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
+ "nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
+ },
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
@@ -2439,6 +2891,9 @@
"invariant": "^2.2.2",
"levenary": "^1.1.1",
"semver": "^5.5.0"
+ },
+ "dependencies": {
+ "node-releases": {}
}
},
"@babel/preset-modules": {
@@ -8206,6 +8661,24 @@
"semver": "^6.0.0"
}
},
+ "make-dir": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+ "dev": true,
+ "requires": {
+ "pify": "^4.0.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -8719,6 +9192,10 @@
"path-exists": "^4.0.0"
}
},
+ "fsevents": {
+ "version": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
+ "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA=="
+ },
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -9856,6 +10333,73 @@
"color-convert": "^2.0.1"
}
},
+ "autoprefixer": {
+ "version": "9.7.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.6.tgz",
+ "integrity": "sha512-F7cYpbN7uVVhACZTeeIeealwdGM6wMtfWARVLTy5xmKtgVdBNJvbDRoCK3YO1orcs7gv/KwYlb3iXwu9Ug9BkQ==",
+ "dev": true,
+ "requires": {
+ "browserslist": "^4.11.1",
+ "caniuse-lite": "^1.0.30001039",
+ "chalk": "^2.4.2",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.27",
+ "postcss-value-parser": "^4.0.3"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
"chalk": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
@@ -9921,6 +10465,7 @@
"universalify": "^1.0.0"
}
},
+ "normalize-package-data": {},
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
diff --git a/projects/ngx-text-diff/src/lib/components/components.module.ts b/projects/ngx-text-diff/src/lib/components/components.module.ts
new file mode 100644
index 0000000..b419c01
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/components.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { LoaderSpinnerComponent } from './loader-spinner/loader-spinner.component';
+import { SideBySideTableComponent } from './side-by-side-table/side-by-side-table.component';
+import { LineByLineTableComponent } from './line-by-line-table/line-by-line-table.component';
+import { DirectivesModule } from '../directives/directives.module';
+import { PipesModule } from '../pipes/pipes.module';
+import { CdkTableModule } from '@angular/cdk/table';
+import { ScrollingModule } from '@angular/cdk/scrolling';
+
+@NgModule({
+ declarations: [LoaderSpinnerComponent, SideBySideTableComponent, LineByLineTableComponent],
+ imports: [CommonModule, CdkTableModule, ScrollingModule, DirectivesModule, PipesModule],
+ exports: [LoaderSpinnerComponent, SideBySideTableComponent, LineByLineTableComponent],
+})
+export class ComponentsModule {}
diff --git a/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.css b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.html b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.html
new file mode 100644
index 0000000..08db190
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.html
@@ -0,0 +1,69 @@
+
+
+
+
+ |
+ |
+
+ {{ row.lineNumber | lineNumber }}
+ |
+
+
+
+
+ |
+
+ {{ row.lineNumberRight | lineNumber }}
+ |
+
+
+
+
+ |
+
+ {{ row.prefix | linePrefix }}
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
diff --git a/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.spec.ts b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.spec.ts
new file mode 100644
index 0000000..5bb4768
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LineByLineTableComponent } from './line-by-line-table.component';
+
+describe('LineByLineTableComponent', () => {
+ let component: LineByLineTableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ LineByLineTableComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LineByLineTableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.ts b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.ts
new file mode 100644
index 0000000..a89301e
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/line-by-line-table/line-by-line-table.component.ts
@@ -0,0 +1,28 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
+import { DiffLineByLineResult, DiffLineResult, DiffPart } from '../../ngx-text-diff.model';
+
+@Component({
+ selector: 'td-line-by-line-table',
+ templateUrl: './line-by-line-table.component.html',
+ styleUrls: ['./line-by-line-table.component.css']
+})
+export class LineByLineTableComponent implements OnInit {
+ @Input() id: string;
+ @Input() data: Observable;
+ @Input() displayedColumns: string[] = ['lineNumber', 'lineNumberRight', 'prefix', 'lineContent'];
+
+ constructor() { }
+
+ ngOnInit(): void {
+ }
+
+ trackTableRows(index, row: DiffLineByLineResult) {
+ return row?.lineNumber ?? index;
+ }
+
+ trackDiffs(index, diff: DiffPart) {
+ return index;
+ }
+
+}
diff --git a/projects/ngx-text-diff/src/lib/loader-spinner/loader-spinner.component.css b/projects/ngx-text-diff/src/lib/components/loader-spinner/loader-spinner.component.css
similarity index 100%
rename from projects/ngx-text-diff/src/lib/loader-spinner/loader-spinner.component.css
rename to projects/ngx-text-diff/src/lib/components/loader-spinner/loader-spinner.component.css
diff --git a/projects/ngx-text-diff/src/lib/loader-spinner/loader-spinner.component.html b/projects/ngx-text-diff/src/lib/components/loader-spinner/loader-spinner.component.html
similarity index 100%
rename from projects/ngx-text-diff/src/lib/loader-spinner/loader-spinner.component.html
rename to projects/ngx-text-diff/src/lib/components/loader-spinner/loader-spinner.component.html
diff --git a/projects/ngx-text-diff/src/lib/loader-spinner/loader-spinner.component.ts b/projects/ngx-text-diff/src/lib/components/loader-spinner/loader-spinner.component.ts
similarity index 100%
rename from projects/ngx-text-diff/src/lib/loader-spinner/loader-spinner.component.ts
rename to projects/ngx-text-diff/src/lib/components/loader-spinner/loader-spinner.component.ts
diff --git a/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.css b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.css
new file mode 100644
index 0000000..b101c5e
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.css
@@ -0,0 +1,99 @@
+.td-table-container {
+ grid-column: 1 / 2;
+ grid-row: 2;
+ width: 100%;
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+.td-table-wrapper {
+ display: flex;
+ width: 200%;
+}
+
+.td-table {
+ border: 1px solid darkgray;
+ max-height: 50vh;
+ width: 100%;
+ max-width: 100%;
+}
+
+.fit-column {
+ width: 1px;
+ white-space: nowrap;
+}
+
+.line-number-col {
+ position: relative; /* I am the fallback */
+
+ /* Give it everything you got! (use an auto prefixer...) */
+ position: -webkit-sticky;
+ position: sticky;
+ left: 0;
+ top: auto;
+ border-right: 1px solid #ddd;
+ color: #999;
+ text-align: right;
+ background-color: #f7f7f7;
+ padding-left: 10px;
+ padding-right: 10px;
+ font-size: 87.5%;
+}
+
+.line-number-col-left {
+ color: #999;
+ padding-left: 10px;
+ padding-right: 10px;
+ text-align: right;
+ background-color: #f7f7f7;
+ font-size: 87.5%;
+}
+
+.insert-row,
+.insert-row > .line-number-col {
+ background-color: #dfd;
+ border-color: #b4e2b4;
+}
+
+.delete-row,
+.delete-row > .line-number-col {
+ background-color: #fee8e9;
+ border-color: #e9aeae;
+}
+
+.empty-row {
+ background-color: #f7f7f7;
+ height: 24px;
+}
+
+.td-table td {
+ border-top: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ white-space: nowrap;
+ max-width: 50%;
+}
+
+pre {
+ margin-bottom: 0;
+}
+
+td.content-col {
+ padding: 0;
+ margin: 0;
+ line-height: 24px;
+}
+
+td.prefix-col {
+ padding-left: 10px;
+ padding-right: 10px;
+ line-height: 24px;
+}
+
+.insert-row > .highlight {
+ background-color: #acf2bd !important;
+}
+
+.delete-row > .highlight {
+ background-color: #fdb8c0 !important;
+}
diff --git a/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.html b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.html
new file mode 100644
index 0000000..7d0208b
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.html
@@ -0,0 +1,56 @@
+
+
+
+
+ |
+ |
+
+ {{ row?.lineNumber | lineNumber }}
+ |
+
+
+
+
+ |
+
+ {{ row?.prefix | linePrefix }}
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
diff --git a/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.spec.ts b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.spec.ts
new file mode 100644
index 0000000..46fd7d1
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SideBySideTableComponent } from './side-by-side-table.component';
+
+describe('SideBySideTableComponent', () => {
+ let component: SideBySideTableComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ SideBySideTableComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(SideBySideTableComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.ts b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.ts
new file mode 100644
index 0000000..d7afea8
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/components/side-by-side-table/side-by-side-table.component.ts
@@ -0,0 +1,27 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
+import { DiffLineResult, DiffPart, DiffTableRowResult } from '../../ngx-text-diff.model';
+
+@Component({
+ selector: 'td-side-by-side-table',
+ templateUrl: './side-by-side-table.component.html',
+ styleUrls: ['./side-by-side-table.component.css'],
+})
+export class SideBySideTableComponent implements OnInit {
+ @Input() id: string;
+ @Input() data: Observable;
+ @Input() displayedColumns: string[] = ['lineNumber', 'prefix', 'lineContent'];
+ @Input() prefix = '';
+
+ constructor() {}
+
+ ngOnInit(): void {}
+
+ trackTableRows(index, row: DiffLineResult) {
+ return row?.lineNumber ?? index;
+ }
+
+ trackDiffs(index, diff: DiffPart) {
+ return index;
+ }
+}
diff --git a/projects/ngx-text-diff/src/lib/directives/directives.module.ts b/projects/ngx-text-diff/src/lib/directives/directives.module.ts
new file mode 100644
index 0000000..668e99e
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/directives/directives.module.ts
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ContainerDirective } from './ngx-text-diff-container.directive';
+
+@NgModule({
+ declarations: [ContainerDirective],
+ imports: [CommonModule],
+ exports: [ContainerDirective],
+})
+export class DirectivesModule {}
diff --git a/projects/ngx-text-diff/src/lib/ngx-text-diff-container.directive.ts b/projects/ngx-text-diff/src/lib/directives/ngx-text-diff-container.directive.ts
similarity index 100%
rename from projects/ngx-text-diff/src/lib/ngx-text-diff-container.directive.ts
rename to projects/ngx-text-diff/src/lib/directives/ngx-text-diff-container.directive.ts
diff --git a/projects/ngx-text-diff/src/lib/format-line.pipe.spec.ts b/projects/ngx-text-diff/src/lib/format-line.pipe.spec.ts
deleted file mode 100644
index d40edb1..0000000
--- a/projects/ngx-text-diff/src/lib/format-line.pipe.spec.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-/*import { FormatLinePipe } from './format-line.pipe';
-
-describe('FormatLinePipe', () => {
- it('create an instance', () => {
- const pipe = new FormatLinePipe();
- expect(pipe).toBeTruthy();
- });
-});*/
diff --git a/projects/ngx-text-diff/src/lib/format-line.pipe.ts b/projects/ngx-text-diff/src/lib/format-line.pipe.ts
deleted file mode 100644
index b7ee634..0000000
--- a/projects/ngx-text-diff/src/lib/format-line.pipe.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { Pipe, PipeTransform } from '@angular/core';
-
-@Pipe({
- name: 'formatLine'
-})
-export class FormatLinePipe implements PipeTransform {
- transform(line: string, diffs?: string[]): string {
- if (!line) {
- return ' ';
- }
- if (!!diffs && diffs.length > 0) {
- /*diffs.forEach(diff => {
- line = line.replace(diff, `${diff}`);
- });*/
- }
- return line
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/"/g, '"')
- .replace(/ /g, ' ');
- }
-}
diff --git a/projects/ngx-text-diff/src/lib/ngx-text-diff.component.html b/projects/ngx-text-diff/src/lib/ngx-text-diff.component.html
index 2c8341b..2945b58 100644
--- a/projects/ngx-text-diff/src/lib/ngx-text-diff.component.html
+++ b/projects/ngx-text-diff/src/lib/ngx-text-diff.component.html
@@ -1,6 +1,5 @@
-
-
-
-
-
-
- |
- {{ row.leftContent?.lineNumber !== -1 ? row.leftContent?.lineNumber : ' ' }}
- |
-
- {{ row.leftContent?.prefix || ' ' }}
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
- |
- {{ row.rightContent?.lineNumber !== -1 ? row.rightContent?.lineNumber : ' ' }}
- |
-
- {{ row.rightContent?.prefix || ' ' }}
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
- | {{ row.leftContent?.lineNumber }} |
- {{ row.rightContent?.lineNumber }} |
-
- {{ row.leftContent?.prefix || row.rightContent?.prefix || ' ' }}
- |
-
-
- |
-
-
- |
-
-
- |
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/projects/ngx-text-diff/src/lib/ngx-text-diff.component.ts b/projects/ngx-text-diff/src/lib/ngx-text-diff.component.ts
index 46bc88b..1816bc7 100644
--- a/projects/ngx-text-diff/src/lib/ngx-text-diff.component.ts
+++ b/projects/ngx-text-diff/src/lib/ngx-text-diff.component.ts
@@ -1,20 +1,31 @@
import {
+ AfterViewInit,
ChangeDetectorRef,
Component,
+ EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
- EventEmitter,
- ViewChildren,
QueryList,
- AfterViewInit
+ ViewChildren,
} from '@angular/core';
-import { DiffContent, DiffPart, DiffTableFormat, DiffTableFormatOption, DiffTableRowResult, DiffResults } from './ngx-text-diff.model';
+import {
+ DiffContent,
+ DiffLineByLineResult,
+ DiffLineResult,
+ DiffPart,
+ DiffResults,
+ DiffTableFormat,
+ DiffTableFormatOption,
+ DiffTableLineByLine,
+ DiffTableRowResult,
+ DiffTableSideBySide,
+} from './ngx-text-diff.model';
import { NgxTextDiffService } from './ngx-text-diff.service';
-import { Observable, Subscription } from 'rxjs';
-import { ContainerDirective } from './ngx-text-diff-container.directive';
-import { ScrollDispatcher, CdkScrollable } from '@angular/cdk/scrolling';
+import { BehaviorSubject, Observable, Subscription } from 'rxjs';
+import { ContainerDirective } from './directives/ngx-text-diff-container.directive';
+import { CdkScrollable, ScrollDispatcher } from '@angular/cdk/scrolling';
@Component({
selector: 'td-ngx-text-diff',
@@ -22,7 +33,6 @@ import { ScrollDispatcher, CdkScrollable } from '@angular/cdk/scrolling';
styleUrls: ['./ngx-text-diff.component.css'],
})
export class NgxTextDiffComponent implements OnInit, AfterViewInit, OnDestroy {
- private _hideMatchingLines = false;
@ViewChildren(ContainerDirective) containers: QueryList
;
@Input() format: DiffTableFormat = 'SideBySide';
@Input() left = '';
@@ -31,14 +41,7 @@ export class NgxTextDiffComponent implements OnInit, AfterViewInit, OnDestroy {
@Input() loading = false;
@Input() showToolbar = true;
@Input() showBtnToolbar = true;
- @Input()
- get hideMatchingLines() {
- return this._hideMatchingLines;
- }
-
- set hideMatchingLines(hide: boolean) {
- this.hideMatchingLinesChanged(hide);
- }
+ @Input() hideMatchingLines = false;
@Input() outerContainerClass: string;
@Input() outerContainerStyle: any;
@Input() toolbarClass: string;
@@ -49,11 +52,17 @@ export class NgxTextDiffComponent implements OnInit, AfterViewInit, OnDestroy {
@Output() compareResults = new EventEmitter();
subscriptions: Subscription[] = [];
tableRows: DiffTableRowResult[] = [];
- filteredTableRows: DiffTableRowResult[] = [];
- tableRowsLineByLine: DiffTableRowResult[] = [];
- filteredTableRowsLineByLine: DiffTableRowResult[] = [];
diffsCount = 0;
+ private _leftContent: BehaviorSubject = new BehaviorSubject([]);
+ leftContent$: Observable = this._leftContent.asObservable();
+
+ private _rightContent: BehaviorSubject = new BehaviorSubject([]);
+ rightContent$: Observable = this._rightContent.asObservable();
+
+ private _lineByLine: BehaviorSubject = new BehaviorSubject([]);
+ lineByLine$: Observable = this._lineByLine.asObservable();
+
formatOptions: DiffTableFormatOption[] = [
{
id: 'side-by-side',
@@ -74,25 +83,17 @@ export class NgxTextDiffComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(private scrollService: ScrollDispatcher, private diff: NgxTextDiffService, private cd: ChangeDetectorRef) {}
ngOnInit() {
- this.loading = true;
if (this.diffContent) {
this.subscriptions.push(
this.diffContent.subscribe(content => {
- this.loading = true;
this.left = content.leftContent;
this.right = content.rightContent;
- this.renderDiffs()
- .then(() => {
- this.cd.detectChanges();
- this.loading = false;
- })
- .catch(() => (this.loading = false));
+ this.initTable();
})
);
}
- this.renderDiffs()
- .then(() => (this.loading = false))
- .catch(e => (this.loading = false));
+
+ this.initTable();
}
ngAfterViewInit() {
@@ -105,81 +106,53 @@ export class NgxTextDiffComponent implements OnInit, AfterViewInit, OnDestroy {
}
}
- hideMatchingLinesChanged(value: boolean) {
- this._hideMatchingLines = value;
- if (this.hideMatchingLines) {
- this.filteredTableRows = this.tableRows.filter(
- row => (row.leftContent && row.leftContent.prefix === '-') || (row.rightContent && row.rightContent.prefix === '+')
- );
- this.filteredTableRowsLineByLine = this.tableRowsLineByLine.filter(
- row => (row.leftContent && row.leftContent.prefix === '-') || (row.rightContent && row.rightContent.prefix === '+')
- );
- } else {
- this.filteredTableRows = this.tableRows;
- this.filteredTableRowsLineByLine = this.tableRowsLineByLine;
+ hideMatchingLinesChanged(hideMatchingLines: boolean) {
+ if (this.hideMatchingLines !== hideMatchingLines) {
+ this.hideMatchingLines = hideMatchingLines;
+ this.populateTable();
}
}
setDiffTableFormat(format: DiffTableFormat) {
- this.format = format;
+ if (format !== this.format) {
+ this.format = format;
+ this.populateTable();
+ }
}
- async renderDiffs() {
- try {
- this.diffsCount = 0;
- this.tableRows = await this.diff.getDiffsByLines(this.left, this.right);
- this.tableRowsLineByLine = this.tableRows.reduce((tableLineByLine: DiffTableRowResult[], row: DiffTableRowResult) => {
- if (!tableLineByLine) {
- tableLineByLine = [];
- }
- if (row.hasDiffs) {
- if (row.leftContent) {
- tableLineByLine.push({
- leftContent: row.leftContent,
- rightContent: null,
- belongTo: row.belongTo,
- hasDiffs: true,
- numDiffs: row.numDiffs,
- });
- }
- if (row.rightContent) {
- tableLineByLine.push({
- leftContent: null,
- rightContent: row.rightContent,
- belongTo: row.belongTo,
- hasDiffs: true,
- numDiffs: row.numDiffs,
- });
- }
- } else {
- tableLineByLine.push(row);
- }
+ initTable() {
+ this.diff
+ .getDiffsByLines(this.left, this.right)
+ .then(results => {
+ this.tableRows = results;
+ this.populateTable();
+ })
+ .catch(err => {
+ this.tableRows = [];
+ this.populateTable();
+ });
+ }
- return tableLineByLine;
- }, []);
- this.diffsCount = this.tableRows.filter(row => row.hasDiffs).length;
- this.filteredTableRows = this.tableRows;
- this.filteredTableRowsLineByLine = this.tableRowsLineByLine;
- this.emitCompareResultsEvent();
- } catch (e) {
- throw e;
+ populateTable() {
+ switch (this.format) {
+ case 'LineByLine':
+ this.populateLineByLineTable();
+ break;
+ case 'SideBySide':
+ this.populateSideBySideTable();
+ break;
}
}
- emitCompareResultsEvent() {
- const diffResults: DiffResults = {
- hasDiff: this.diffsCount > 0,
- diffsCount: this.diffsCount,
- rowsWithDiff: this.tableRows
- .filter(row => row.hasDiffs)
- .map(row => ({
- leftLineNumber: row.leftContent ? row.leftContent.lineNumber : null,
- rightLineNumber: row.rightContent ? row.rightContent.lineNumber : null,
- numDiffs: row.numDiffs,
- })),
- };
-
- this.compareResults.next(diffResults);
+ private populateSideBySideTable() {
+ const results: DiffTableSideBySide = this.diff.getSideBySide(this.tableRows, this.hideMatchingLines);
+ this._leftContent.next(results.left);
+ this._rightContent.next(results.right);
+ }
+
+ private populateLineByLineTable() {
+ const results: DiffTableLineByLine = this.diff.getLineByLine(this.tableRows, this.hideMatchingLines);
+ this._lineByLine.next(results.rows);
}
trackTableRows(index, row: DiffTableRowResult) {
@@ -191,17 +164,19 @@ export class NgxTextDiffComponent implements OnInit, AfterViewInit, OnDestroy {
}
private initScrollListener() {
- this.subscriptions.push(this.scrollService.scrolled().subscribe((scrollableEv: CdkScrollable) => {
- if (scrollableEv && this.synchronizeScrolling) {
- const scrollableId = scrollableEv.getElementRef().nativeElement.id;
- const nonScrolledContainer: ContainerDirective = this.containers.find(container => container.id !== scrollableId);
- if (nonScrolledContainer) {
- nonScrolledContainer.element.scrollTo({
- top: scrollableEv.measureScrollOffset('top'),
- left: scrollableEv.measureScrollOffset('left'),
- });
+ this.subscriptions.push(
+ this.scrollService.scrolled().subscribe((scrollableEv: CdkScrollable) => {
+ if (scrollableEv && this.synchronizeScrolling) {
+ const scrollableId = scrollableEv.getElementRef().nativeElement.id;
+ const nonScrolledContainer: ContainerDirective = this.containers.find(container => container.id !== scrollableId);
+ if (nonScrolledContainer) {
+ nonScrolledContainer.element.scrollTo({
+ top: scrollableEv.measureScrollOffset('top'),
+ left: scrollableEv.measureScrollOffset('left'),
+ });
+ }
}
- }
- }));
+ })
+ );
}
}
diff --git a/projects/ngx-text-diff/src/lib/ngx-text-diff.model.ts b/projects/ngx-text-diff/src/lib/ngx-text-diff.model.ts
index 7f0c9f3..b824efb 100644
--- a/projects/ngx-text-diff/src/lib/ngx-text-diff.model.ts
+++ b/projects/ngx-text-diff/src/lib/ngx-text-diff.model.ts
@@ -27,6 +27,20 @@ export interface DiffLineResult {
lineDiffs: DiffPart[];
}
+export interface DiffTableSideBySide {
+ left: DiffLineResult[];
+ right: DiffLineResult[];
+}
+
+export interface DiffTableLineByLine {
+ rows: DiffLineByLineResult[];
+}
+
+export interface DiffLineByLineResult extends DiffLineResult {
+ lineNumber: number;
+ lineNumberRight: number;
+}
+
export interface DiffTableRowResult {
leftContent: DiffLineResult;
rightContent: DiffLineResult;
diff --git a/projects/ngx-text-diff/src/lib/ngx-text-diff.module.ts b/projects/ngx-text-diff/src/lib/ngx-text-diff.module.ts
index 8522567..648aa83 100644
--- a/projects/ngx-text-diff/src/lib/ngx-text-diff.module.ts
+++ b/projects/ngx-text-diff/src/lib/ngx-text-diff.module.ts
@@ -2,14 +2,15 @@ import { NgModule } from '@angular/core';
import { NgxTextDiffComponent } from './ngx-text-diff.component';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
-import { LoaderSpinnerComponent } from './loader-spinner/loader-spinner.component';
-import { FormatLinePipe } from './format-line.pipe';
-import { ContainerDirective } from './ngx-text-diff-container.directive';
import { ScrollingModule } from '@angular/cdk/scrolling';
+import { CdkTableModule } from '@angular/cdk/table';
+import { DirectivesModule } from './directives/directives.module';
+import { PipesModule } from './pipes/pipes.module';
+import { ComponentsModule } from './components/components.module';
@NgModule({
- imports: [CommonModule, FormsModule, ScrollingModule],
- declarations: [NgxTextDiffComponent, LoaderSpinnerComponent, FormatLinePipe, ContainerDirective],
+ imports: [CommonModule, FormsModule, ScrollingModule, CdkTableModule, DirectivesModule, PipesModule, ComponentsModule],
+ declarations: [NgxTextDiffComponent],
exports: [NgxTextDiffComponent],
})
export class NgxTextDiffModule {}
diff --git a/projects/ngx-text-diff/src/lib/ngx-text-diff.service.ts b/projects/ngx-text-diff/src/lib/ngx-text-diff.service.ts
index c8a34c4..73431a6 100644
--- a/projects/ngx-text-diff/src/lib/ngx-text-diff.service.ts
+++ b/projects/ngx-text-diff/src/lib/ngx-text-diff.service.ts
@@ -1,10 +1,10 @@
import { Injectable } from '@angular/core';
import { Diff, DIFF_DELETE, DIFF_EQUAL, DIFF_INSERT, diff_match_patch } from 'diff-match-patch';
-import { DiffLineResult, DiffPart, DiffTableRowResult } from './ngx-text-diff.model';
-import { isEmpty, isNil } from './ngx-text-diff.utils';
+import { DiffLineResult, DiffPart, DiffTableLineByLine, DiffTableRowResult, DiffTableSideBySide } from './ngx-text-diff.model';
+import { isEmpty } from './ngx-text-diff.utils';
@Injectable({
- providedIn: 'root'
+ providedIn: 'root',
})
export class NgxTextDiffService {
diffParser: diff_match_patch;
@@ -17,21 +17,19 @@ export class NgxTextDiffService {
this.diffParser = new diff_match_patch();
}
- getDiffsByLines(left: string, right: string): Promise {
- return new Promise((resolve, reject) => {
- const a = this.diffParser.diff_linesToChars_(left, right);
- const lineText1 = a.chars1;
- const lineText2 = a.chars2;
- const linesArray = a.lineArray;
- const diffs: Diff[] = this.diffParser.diff_main(lineText1, lineText2, true);
- this.diffParser.diff_charsToLines_(diffs, linesArray);
- const rows: DiffTableRowResult[] = this.formatOutput(diffs);
- if (!rows) {
- reject('Error');
- }
+ async getDiffsByLines(left: string, right: string): Promise {
+ const a = this.diffParser.diff_linesToChars_(left, right);
+ const lineText1 = a.chars1;
+ const lineText2 = a.chars2;
+ const linesArray = a.lineArray;
+ const diffs: Diff[] = this.diffParser.diff_main(lineText1, lineText2, true);
+ this.diffParser.diff_charsToLines_(diffs, linesArray);
+ const rows: DiffTableRowResult[] = this.formatOutput(diffs);
+ if (!rows) {
+ throw new Error('Error');
+ }
- resolve(rows);
- });
+ return rows;
}
private formatOutput(diffs: Diff[]): DiffTableRowResult[] {
@@ -63,13 +61,13 @@ export class NgxTextDiffService {
lineNumber: lineLeft,
lineContent: line,
lineDiffs: [],
- prefix: ''
+ prefix: '',
};
rightContent = {
lineNumber: lineRight,
lineContent: line,
lineDiffs: [],
- prefix: ''
+ prefix: '',
};
rowTemp = {
leftContent,
@@ -100,7 +98,7 @@ export class NgxTextDiffService {
lineNumber: lineLeft,
lineContent: line,
lineDiffs: [{ content: line, isDiff: true }],
- prefix: '-'
+ prefix: '-',
};
if (rightDiffRow) {
rightDiffRow.leftContent = leftContent;
@@ -143,7 +141,7 @@ export class NgxTextDiffService {
lineNumber: lineRight,
lineContent: line,
lineDiffs: [{ content: line, isDiff: true }],
- prefix: '+'
+ prefix: '+',
};
if (leftDiffRow) {
leftDiffRow.rightContent = rightContent;
@@ -179,7 +177,7 @@ export class NgxTextDiffService {
if (result.leftContent) {
diffCount += result.leftContent.lineDiffs.filter(diff => diff.isDiff).length;
}
- if (result.leftContent) {
+ if (result.rightContent) {
diffCount += result.rightContent.lineDiffs.filter(diff => diff.isDiff).length;
}
return diffCount;
@@ -218,4 +216,59 @@ export class NgxTextDiffService {
return diffParts;
}
+
+ getSideBySide(rows: DiffTableRowResult[], onlyDiffs = false): DiffTableSideBySide {
+ return rows
+ .filter(row => !onlyDiffs || row.hasDiffs)
+ .reduce(
+ (temp: DiffTableSideBySide, row: DiffTableRowResult) => {
+ temp.left.push(row.leftContent);
+ temp.right.push(row.rightContent);
+
+ return temp;
+ },
+ { left: [], right: [] }
+ );
+ }
+
+ getLineByLine(rows: DiffTableRowResult[], onlyDiffs = false): DiffTableLineByLine {
+ return rows
+ .filter(row => !onlyDiffs || row.hasDiffs)
+ .reduce(
+ (temp: DiffTableLineByLine, row: DiffTableRowResult) => {
+ const { leftContent, rightContent, hasDiffs } = row;
+ if (!hasDiffs) {
+ temp.rows.push({
+ lineNumber: leftContent?.lineNumber,
+ lineNumberRight: rightContent?.lineNumber,
+ lineContent: leftContent?.lineContent,
+ prefix: leftContent?.prefix,
+ lineDiffs: [],
+ });
+ } else {
+ if (!!leftContent) {
+ temp.rows.push({
+ lineNumber: leftContent.lineNumber,
+ lineNumberRight: -1,
+ lineContent: leftContent.lineContent,
+ prefix: leftContent.prefix,
+ lineDiffs: leftContent.lineDiffs,
+ });
+ }
+ if (!!rightContent) {
+ temp.rows.push({
+ lineNumber: -1,
+ lineNumberRight: rightContent.lineNumber,
+ lineContent: rightContent.lineContent,
+ prefix: rightContent.prefix,
+ lineDiffs: rightContent.lineDiffs,
+ });
+ }
+ }
+
+ return temp;
+ },
+ { rows: [] }
+ );
+ }
}
diff --git a/projects/ngx-text-diff/src/lib/pipes/line-content.pipe.spec.ts b/projects/ngx-text-diff/src/lib/pipes/line-content.pipe.spec.ts
new file mode 100644
index 0000000..d369bb9
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/line-content.pipe.spec.ts
@@ -0,0 +1,8 @@
+import { LineContentPipe } from './line-content.pipe';
+
+describe('LineContentPipe', () => {
+ it('create an instance', () => {
+ const pipe = new LineContentPipe();
+ expect(pipe).toBeTruthy();
+ });
+});
diff --git a/projects/ngx-text-diff/src/lib/pipes/line-content.pipe.ts b/projects/ngx-text-diff/src/lib/pipes/line-content.pipe.ts
new file mode 100644
index 0000000..8383bca
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/line-content.pipe.ts
@@ -0,0 +1,14 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'lineContent',
+})
+export class LineContentPipe implements PipeTransform {
+ transform(line: string, diffs?: string[]): string {
+ if (!line) {
+ return ' ';
+ }
+
+ return line.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/ /g, ' ');
+ }
+}
diff --git a/projects/ngx-text-diff/src/lib/pipes/line-number.pipe.spec.ts b/projects/ngx-text-diff/src/lib/pipes/line-number.pipe.spec.ts
new file mode 100644
index 0000000..d5f1664
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/line-number.pipe.spec.ts
@@ -0,0 +1,8 @@
+import { LineNumberPipe } from './line-number.pipe';
+
+describe('LineNumberPipe', () => {
+ it('create an instance', () => {
+ const pipe = new LineNumberPipe();
+ expect(pipe).toBeTruthy();
+ });
+});
diff --git a/projects/ngx-text-diff/src/lib/pipes/line-number.pipe.ts b/projects/ngx-text-diff/src/lib/pipes/line-number.pipe.ts
new file mode 100644
index 0000000..1c29a12
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/line-number.pipe.ts
@@ -0,0 +1,10 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'lineNumber',
+})
+export class LineNumberPipe implements PipeTransform {
+ transform(value: number, ...args: unknown[]): number | string {
+ return value !== -1 ? value : ' ';
+ }
+}
diff --git a/projects/ngx-text-diff/src/lib/pipes/line-prefix.pipe.spec.ts b/projects/ngx-text-diff/src/lib/pipes/line-prefix.pipe.spec.ts
new file mode 100644
index 0000000..5aa0ef3
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/line-prefix.pipe.spec.ts
@@ -0,0 +1,8 @@
+import { LinePrefixPipe } from './line-prefix.pipe';
+
+describe('LinePrefixPipe', () => {
+ it('create an instance', () => {
+ const pipe = new LinePrefixPipe();
+ expect(pipe).toBeTruthy();
+ });
+});
diff --git a/projects/ngx-text-diff/src/lib/pipes/line-prefix.pipe.ts b/projects/ngx-text-diff/src/lib/pipes/line-prefix.pipe.ts
new file mode 100644
index 0000000..285f9ab
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/line-prefix.pipe.ts
@@ -0,0 +1,12 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+ name: 'linePrefix'
+})
+export class LinePrefixPipe implements PipeTransform {
+
+ transform(value: string, ...args: unknown[]): string {
+ return value ?? ' ';
+ }
+
+}
diff --git a/projects/ngx-text-diff/src/lib/pipes/pipes.module.ts b/projects/ngx-text-diff/src/lib/pipes/pipes.module.ts
new file mode 100644
index 0000000..2f04bd1
--- /dev/null
+++ b/projects/ngx-text-diff/src/lib/pipes/pipes.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { LineNumberPipe } from './line-number.pipe';
+import { LineContentPipe } from './line-content.pipe';
+import { LinePrefixPipe } from './line-prefix.pipe';
+
+@NgModule({
+ declarations: [LineNumberPipe, LineContentPipe, LinePrefixPipe],
+ imports: [CommonModule],
+ exports: [LineNumberPipe, LineContentPipe, LinePrefixPipe],
+})
+export class PipesModule {}
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index c7a3b7b..0b7b7e1 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -52,9 +52,8 @@ export class HomeComponent implements OnInit {
}
submitComparison() {
- this.submitted = false;
- this.contentObservable.next(this.content);
this.submitted = true;
+ this.contentObservable.next(this.content);
}
handleChange(side: 'left' | 'right', value: string) {