HM-30. Добавлен класс Компонент, поправлены api, внедрен тестовый ком… (#5)
This commit is contained in:
6
.babelrc
6
.babelrc
@ -1,3 +1,7 @@
|
|||||||
{
|
{
|
||||||
"presets": ["@babel/preset-env"]
|
"presets": ["@babel/preset-env"],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-syntax-class-properties",
|
||||||
|
"@babel/plugin-proposal-class-properties"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
6
.eslintignore
Normal file
6
.eslintignore
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/node_modules
|
||||||
|
/dist
|
||||||
|
/out
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
webpack.config.js
|
||||||
@ -1,4 +1,5 @@
|
|||||||
module.exports = {
|
{
|
||||||
|
"parser": "babel-eslint",
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es2020": true
|
"es2020": true
|
||||||
@ -9,5 +10,8 @@ module.exports = {
|
|||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"no-console": "warn",
|
||||||
|
"semi": "error",
|
||||||
|
"quotes": ["error", "single"]
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,4 +3,4 @@
|
|||||||
/dist
|
/dist
|
||||||
/node_modules
|
/node_modules
|
||||||
|
|
||||||
.DS_Store
|
**.DS_Store
|
||||||
|
|||||||
150
package-lock.json
generated
150
package-lock.json
generated
@ -1638,6 +1638,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"babel-eslint": {
|
||||||
|
"version": "10.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
|
||||||
|
"integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/code-frame": "^7.0.0",
|
||||||
|
"@babel/parser": "^7.7.0",
|
||||||
|
"@babel/traverse": "^7.7.0",
|
||||||
|
"@babel/types": "^7.7.0",
|
||||||
|
"eslint-visitor-keys": "^1.0.0",
|
||||||
|
"resolve": "^1.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-loader": {
|
"babel-loader": {
|
||||||
"version": "8.1.0",
|
"version": "8.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz",
|
||||||
@ -2551,6 +2565,15 @@
|
|||||||
"integrity": "sha512-ufHZNtMaDEuRBpTbqD93tIQnngmJ+oBknjvr0IbFympSdtFpAUFmNv4mVKbb53qltxFx0nK3iy32S9AqkLzUNA==",
|
"integrity": "sha512-ufHZNtMaDEuRBpTbqD93tIQnngmJ+oBknjvr0IbFympSdtFpAUFmNv4mVKbb53qltxFx0nK3iy32S9AqkLzUNA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"catharsis": {
|
||||||
|
"version": "0.8.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz",
|
||||||
|
"integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"caw": {
|
"caw": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz",
|
||||||
@ -6137,6 +6160,51 @@
|
|||||||
"esprima": "^4.0.0"
|
"esprima": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"js2xmlparser": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"xmlcreate": "^2.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsdoc": {
|
||||||
|
"version": "3.6.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.4.tgz",
|
||||||
|
"integrity": "sha512-3G9d37VHv7MFdheviDCjUfQoIjdv4TC5zTTf5G9VODLtOnVS6La1eoYBDlbWfsRT3/Xo+j2MIqki2EV12BZfwA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@babel/parser": "^7.9.4",
|
||||||
|
"bluebird": "^3.7.2",
|
||||||
|
"catharsis": "^0.8.11",
|
||||||
|
"escape-string-regexp": "^2.0.0",
|
||||||
|
"js2xmlparser": "^4.0.1",
|
||||||
|
"klaw": "^3.0.0",
|
||||||
|
"markdown-it": "^10.0.0",
|
||||||
|
"markdown-it-anchor": "^5.2.7",
|
||||||
|
"marked": "^0.8.2",
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"requizzle": "^0.2.3",
|
||||||
|
"strip-json-comments": "^3.1.0",
|
||||||
|
"taffydb": "2.6.2",
|
||||||
|
"underscore": "~1.10.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"escape-string-regexp": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jsesc": {
|
"jsesc": {
|
||||||
"version": "2.5.2",
|
"version": "2.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||||
@ -6211,6 +6279,15 @@
|
|||||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"klaw": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
"leven": {
|
"leven": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||||
@ -6236,6 +6313,15 @@
|
|||||||
"type-check": "~0.4.0"
|
"type-check": "~0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"linkify-it": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"uc.micro": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"load-json-file": {
|
"load-json-file": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||||
@ -6406,6 +6492,31 @@
|
|||||||
"object-visit": "^1.0.0"
|
"object-visit": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"markdown-it": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"argparse": "^1.0.7",
|
||||||
|
"entities": "~2.0.0",
|
||||||
|
"linkify-it": "^2.0.0",
|
||||||
|
"mdurl": "^1.0.1",
|
||||||
|
"uc.micro": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"markdown-it-anchor": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"marked": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz",
|
||||||
|
"integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"md5.js": {
|
"md5.js": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||||
@ -6424,6 +6535,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"mdurl": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"media-typer": {
|
"media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
@ -8031,6 +8148,15 @@
|
|||||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
|
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"requizzle": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.17.0",
|
"version": "1.17.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
|
||||||
@ -9106,6 +9232,12 @@
|
|||||||
"string-width": "^3.0.0"
|
"string-width": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"taffydb": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
|
||||||
|
"integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"tapable": {
|
"tapable": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
|
||||||
@ -9382,6 +9514,12 @@
|
|||||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"uc.micro": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"unbzip2-stream": {
|
"unbzip2-stream": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
|
||||||
@ -9406,6 +9544,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"underscore": {
|
||||||
|
"version": "1.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz",
|
||||||
|
"integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"unicode-canonical-property-names-ecmascript": {
|
"unicode-canonical-property-names-ecmascript": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
|
||||||
@ -10223,6 +10367,12 @@
|
|||||||
"async-limiter": "~1.0.0"
|
"async-limiter": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"xmlcreate": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"xtend": {
|
"xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
|||||||
@ -20,7 +20,10 @@
|
|||||||
"homepage": "https://github.com/vigdorov/storage-service-ui#readme",
|
"homepage": "https://github.com/vigdorov/storage-service-ui#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.10.4",
|
"@babel/core": "^7.10.4",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||||
|
"@babel/plugin-syntax-class-properties": "^7.10.4",
|
||||||
"@babel/preset-env": "^7.10.4",
|
"@babel/preset-env": "^7.10.4",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"css-loader": "^3.6.0",
|
"css-loader": "^3.6.0",
|
||||||
@ -28,6 +31,7 @@
|
|||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"image-webpack-loader": "^6.0.0",
|
"image-webpack-loader": "^6.0.0",
|
||||||
|
"jsdoc": "^3.6.4",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
"mini-css-extract-plugin": "^0.9.0",
|
||||||
"url-loader": "^4.1.0",
|
"url-loader": "^4.1.0",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
|
|||||||
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
@ -1,9 +1,16 @@
|
|||||||
|
import {v4 as uuidv4} from 'uuid';
|
||||||
|
|
||||||
import StorageServiceApi from './StorageServiceAPI';
|
import StorageServiceApi from './StorageServiceAPI';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Element
|
||||||
|
* @type {object}
|
||||||
|
* @property {string} _id - уникальный id элемента
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Класс создания api для списков данных
|
* Класс создания api для списков данных
|
||||||
* @class
|
* @class
|
||||||
* @public
|
|
||||||
*/
|
*/
|
||||||
class StorageListApi {
|
class StorageListApi {
|
||||||
/**
|
/**
|
||||||
@ -16,33 +23,47 @@ class StorageListApi {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
|
*
|
||||||
|
* @param {Array.<Element>} list - список элементов по которым осуществялется поиск
|
||||||
* @param {string} _id - _id искомого элемента
|
* @param {string} _id - _id искомого элемента
|
||||||
*
|
*
|
||||||
|
* @returns {number} - Возвращает индекс искомого эллемента по _id
|
||||||
* @returns {Promise<Object, string>}
|
|
||||||
*/
|
*/
|
||||||
async _findIndex(_id) {
|
_findIndex = (list, _id) => {
|
||||||
const list = await this.request();
|
|
||||||
return list.findIndex(item => item._id === _id);
|
return list.findIndex(item => item._id === _id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @private
|
||||||
* @returns {Promise} - возвращает все элементы списка
|
*
|
||||||
|
* @param {Array<Element>} list - новый список элементов
|
||||||
|
*
|
||||||
|
* @returns {Promise<Array<Element>>} - возвращает обновленный список элементов
|
||||||
*/
|
*/
|
||||||
async request() {
|
_updateList = async (list) => {
|
||||||
|
return await this.api.createOrUpdate(this.key, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {Promise<Array<Element>>} - возвращает все элементы списка
|
||||||
|
*/
|
||||||
|
request = async () => {
|
||||||
const data = await this.api.find(this.key);
|
const data = await this.api.find(this.key);
|
||||||
return (data && data.value) || [];
|
return (data && data.value) || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
* @param {string} _id - _id искомого элемента списка
|
* @param {string} _id - _id искомого элемента списка
|
||||||
*
|
*
|
||||||
* @returns {Promise} - возвращает элемент списка или генерит ошибку
|
* @returns {Promise<Element>} - возвращает элемент списка или генерит ошибку
|
||||||
*/
|
*/
|
||||||
async find(_id) {
|
find = async (_id) => {
|
||||||
const list = await this.request();
|
const list = await this.request();
|
||||||
const findIndex = LocalStorageListApi.findIndex(list, _id);
|
const findIndex = this._findIndex(list, _id);
|
||||||
if (findIndex === -1) {
|
if (findIndex === -1) {
|
||||||
throw new Error(`Not Found _id: ${_id}`);
|
throw new Error(`Not Found _id: ${_id}`);
|
||||||
}
|
}
|
||||||
@ -50,51 +71,58 @@ class StorageListApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
* @param {Object} data - элемент списка
|
* @param {Object} data - элемент списка
|
||||||
*
|
*
|
||||||
* @returns {Promise} - Возвращает вновь созданный элемент с уникальным полем _id
|
* @returns {Promise<Element>} - Возвращает вновь созданный элемент с уникальным полем _id
|
||||||
*/
|
*/
|
||||||
async create(data) {
|
create = async (data) => {
|
||||||
const list = await this.request();
|
const list = await this.request();
|
||||||
const _id = uuidv4();
|
const _id = uuidv4();
|
||||||
const newData = {
|
const newData = {
|
||||||
...data,
|
...data,
|
||||||
_id,
|
_id,
|
||||||
};
|
};
|
||||||
await this.api.createOrUpdate(this.key, list.concat(newData));
|
await this._updateList(list.concat(newData));
|
||||||
return newData;
|
return newData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} data - элемент списка
|
* @public
|
||||||
* @param {string} data._id - наличие _id обязательно
|
|
||||||
*
|
*
|
||||||
* @returns {Promise} - Возвращает обновленный элемент списка
|
* @param {Element} data - элемент списка
|
||||||
|
*
|
||||||
|
* @returns {Promise<Element>} - Возвращает обновленный элемент списка
|
||||||
*/
|
*/
|
||||||
async update(data) {
|
update = async (data) => {
|
||||||
const list = await this.request();
|
const list = await this.request();
|
||||||
const findIndex = LocalStorageListApi.findIndex(list, data._id);
|
const findIndex = this._findIndex(list, data._id);
|
||||||
if (findIndex === -1) {
|
if (findIndex === -1) {
|
||||||
throw new Error(`Not Found _id: ${data._id}`);
|
throw new Error(`Not Found _id: ${data._id}`);
|
||||||
}
|
}
|
||||||
list.splice(findIndex, 1, data);
|
list.splice(findIndex, 1, data);
|
||||||
await this.api.createOrUpdate(this.key, list);
|
await this._updateList(list);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
* @param {string} _id - _id удаляемого элемента
|
* @param {string} _id - _id удаляемого элемента
|
||||||
*
|
*
|
||||||
* @returns {Promise} - Возвращает _id удаленного элемента или ошибку
|
* @returns {Promise<string>} - Возвращает _id удаленного элемента или ошибку
|
||||||
*/
|
*/
|
||||||
async remove(_id) {
|
remove = async (_id) => {
|
||||||
const list = await this.request();
|
const list = await this.request();
|
||||||
const findIndex = LocalStorageListApi.findIndex(list, _id);
|
const findIndex = this._findIndex(list, _id);
|
||||||
if (findIndex === -1) {
|
if (findIndex === -1) {
|
||||||
throw new Error(`Not Found _id: ${_id}`);
|
throw new Error(`Not Found _id: ${_id}`);
|
||||||
}
|
}
|
||||||
list.splice(findIndex, 1);
|
list.splice(findIndex, 1);
|
||||||
await this.api.createOrUpdate(this.key, list);
|
await this._updateList(list);
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default StorageListApi;
|
||||||
|
|||||||
@ -1,25 +1,64 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
import {API_URL, ENDPOINT} from './consts';
|
import {API_URL, ENDPOINT} from './consts';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Store
|
||||||
|
* @type {object}
|
||||||
|
* @property {string} key
|
||||||
|
* @property {unknown} value
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс для работы с store-service api
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
class StorageServiceApi {
|
class StorageServiceApi {
|
||||||
URL = `${API_URL}${ENDPOINT}`;
|
URL = `${API_URL}${ENDPOINT}`;
|
||||||
|
|
||||||
async request() {
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @returns {Promise<Array<Store>>} - Возвращает список всех пар ключ-значение
|
||||||
|
*/
|
||||||
|
request = async () => {
|
||||||
const {data} = await axios.get(this.URL);
|
const {data} = await axios.get(this.URL);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async find(key) {
|
/**
|
||||||
const {data} = await axios.get(`${this.URL}/${key}`)
|
* @public
|
||||||
|
*
|
||||||
|
* @param {string} key - ключ хранилища в api
|
||||||
|
*
|
||||||
|
* @returns {Promise<unknown>} - Возвращает значение по указанному ключу
|
||||||
|
*/
|
||||||
|
find = async (key) => {
|
||||||
|
const {data} = await axios.get(`${this.URL}/${key}`);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async createOrUpdate(key, value) {
|
/**
|
||||||
const {data} = await axios.post(this.URL, {key, value})
|
* @public
|
||||||
|
*
|
||||||
|
* @param {string} key - ключ хранилища в api
|
||||||
|
* @param {unknown} value - значение, которое будет хранится под указанным ключом
|
||||||
|
*
|
||||||
|
* @returns {Promise<unknown>} - возвращает вновь созданный элемент
|
||||||
|
*/
|
||||||
|
createOrUpdate = async (key, value) => {
|
||||||
|
const {data} = await axios.post(this.URL, {key, value});
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(key) {
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @param {string} key - ключ хранилища api
|
||||||
|
*
|
||||||
|
* @returns {Promise<string>} - возвращает 'ok', если удаление было выполнено
|
||||||
|
*/
|
||||||
|
remove = async (key) => {
|
||||||
const {data} = await axios.delete(`${this.URL}/${key}`);
|
const {data} = await axios.delete(`${this.URL}/${key}`);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
export const API_URL = 'http://vigdorov.ru:4001';
|
export const API_URL = 'http://vigdorov.ru:4001';
|
||||||
export const ENDPOINT = '/store';
|
|
||||||
export const API_KEYS = {
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
export const ENDPOINT = '/store';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Object<string, string>}
|
||||||
|
*/
|
||||||
|
export const API_KEYS = {
|
||||||
};
|
};
|
||||||
21
src/app.html
21
src/app.html
@ -1,11 +1,26 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<!-- Шаблон Модального окна -->
|
||||||
|
<template id="test-modal">
|
||||||
|
<div class="TestModal">
|
||||||
|
<div class="TestModal__shadow"></div>
|
||||||
|
<div class="TestModal__window"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Шаблон кнопки -->
|
||||||
|
<template id="test-button">
|
||||||
|
<button type="button" class="btn btn-primary">Жми меня для теста</button>
|
||||||
|
</template>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
11
src/app.js
11
src/app.js
@ -1,3 +1,14 @@
|
|||||||
import './app.css';
|
import './app.css';
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||||
import 'bootstrap';
|
import 'bootstrap';
|
||||||
|
|
||||||
|
// ! TODO: 5-14 строчки удалить, после теста компонента
|
||||||
|
import TestModal from './components/test-modal';
|
||||||
|
import TestButton from './components/test-button';
|
||||||
|
|
||||||
|
const testModal = new TestModal();
|
||||||
|
const testButton = new TestButton();
|
||||||
|
|
||||||
|
testButton.subscribe('click', () => {
|
||||||
|
testModal.show();
|
||||||
|
});
|
||||||
|
|||||||
118
src/components/component/Component.js
Normal file
118
src/components/component/Component.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* @typedef Listener
|
||||||
|
* @type {Object}
|
||||||
|
* @property {Node} element
|
||||||
|
* @property {string} eventName
|
||||||
|
* @property {function} listener
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function EventListener
|
||||||
|
* @param {unknown[]} args - аргументы функции
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Events
|
||||||
|
* @type {Object<string, EventListener[]>}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Класс для создания компонентов приложения. Необходим для нследования.
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
class Component {
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Listener[]}
|
||||||
|
*/
|
||||||
|
_listeners;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Events}
|
||||||
|
*/
|
||||||
|
_events;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
* @type {Node} - корневой элемент компонента
|
||||||
|
*/
|
||||||
|
mainNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} mainNodeSelector - селектор, с помощью которого извлекается шаблон компонента
|
||||||
|
* @param {Node} parentNode - родительский Node, в который следует положить созданный элемент
|
||||||
|
*/
|
||||||
|
constructor(mainNodeSelector, parentNode) {
|
||||||
|
/**
|
||||||
|
* @type {DocumentFragment}
|
||||||
|
*/
|
||||||
|
const content = document.querySelector(mainNodeSelector).content;
|
||||||
|
if (content.children.length > 1) {
|
||||||
|
const message = '<template> должен содержать только один элемент children';
|
||||||
|
alert(message);
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
this.mainNode = content.firstElementChild.cloneNode(true);
|
||||||
|
parentNode.appendChild(this.mainNode);
|
||||||
|
this._listeners = [];
|
||||||
|
this._events = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод добавления обработчиков события на Node'ы компонента
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @param {Node} element - элемент, на который будет навешен обработчик
|
||||||
|
* @param {string} eventName - событие, на которое будет реагировать обработчик
|
||||||
|
* @param {function} listener - обработчик события
|
||||||
|
*/
|
||||||
|
addEventListener = (element, eventName, listener) => {
|
||||||
|
element.addEventListener(eventName, listener);
|
||||||
|
this._listeners.push({element, eventName, listener});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод подписки на события компонента
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @param {string} eventName - событие компонента, на которое будет реагировать обработчик
|
||||||
|
* @param {EventListener} listener - обработчик события
|
||||||
|
*/
|
||||||
|
subscribe = (eventName, listener) => {
|
||||||
|
const listeners = this._events[eventName] || [];
|
||||||
|
this._events[eventName] = [
|
||||||
|
...listeners,
|
||||||
|
listener,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод генерирует событие
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* @param {string} eventName - событие, которое необходимо сгенерировать
|
||||||
|
* @param {unknown[]} args - аругемнты, который необходимо передать обработчикам события
|
||||||
|
*/
|
||||||
|
next = (eventName, ...args) => {
|
||||||
|
const listeners = this._events[eventName];
|
||||||
|
listeners.forEach(listener => {
|
||||||
|
listener(...args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод уничтожения компонента. Удаляет элемент из верстки, снимает обработчики и очищает подписки
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
destroy = () => {
|
||||||
|
this._listeners.forEach(({element, eventName, listener}) => {
|
||||||
|
element.removeEventListener(eventName, listener);
|
||||||
|
});
|
||||||
|
this.mainNode.remove();
|
||||||
|
this._listeners = [];
|
||||||
|
this._events = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Component;
|
||||||
3
src/components/component/index.js
Normal file
3
src/components/component/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import Component from './Component';
|
||||||
|
|
||||||
|
export default Component;
|
||||||
15
src/components/test-button/TestButton.js
Normal file
15
src/components/test-button/TestButton.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// ! TODO: Удалить, необходим для примера работы с компонентами
|
||||||
|
|
||||||
|
import Component from '../component';
|
||||||
|
|
||||||
|
class TestButton extends Component {
|
||||||
|
constructor() {
|
||||||
|
super('#test-button', document.body);
|
||||||
|
|
||||||
|
this.addEventListener(this.mainNode, 'click', (evt) => {
|
||||||
|
this.next('click', evt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TestButton;
|
||||||
3
src/components/test-button/index.js
Normal file
3
src/components/test-button/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import TestButton from './TestButton';
|
||||||
|
|
||||||
|
export default TestButton;
|
||||||
31
src/components/test-modal/TestModal.css
Normal file
31
src/components/test-modal/TestModal.css
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.TestModal {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TestModal_hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TestModal__shadow {
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TestModal__window {
|
||||||
|
width: 300px;
|
||||||
|
height: 200px;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
38
src/components/test-modal/TestModal.js
Normal file
38
src/components/test-modal/TestModal.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// ! TODO: Удалить, необходим для примера работы с компонентами
|
||||||
|
import Component from '../component';
|
||||||
|
|
||||||
|
import './TestModal.css';
|
||||||
|
|
||||||
|
const MAIN = 'TestModal';
|
||||||
|
const CN = {
|
||||||
|
SHADOW: `${MAIN}__shadow`,
|
||||||
|
WINDOW: `${MAIN}__window`,
|
||||||
|
HIDE_MODAL: `${MAIN}_hide`,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestModal extends Component {
|
||||||
|
constructor() {
|
||||||
|
super('#test-modal', document.body);
|
||||||
|
|
||||||
|
this.shadow = this.mainNode.querySelector(`.${CN.SHADOW}`);
|
||||||
|
this.window = this.mainNode.querySelector(`.${CN.WINDOW}`);
|
||||||
|
|
||||||
|
this.addEventListener(this.shadow, 'click', (evt) => {
|
||||||
|
if (evt.target === this.shadow) {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
show = () => {
|
||||||
|
this.mainNode.classList.remove(CN.HIDE_MODAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide = () => {
|
||||||
|
this.mainNode.classList.add(CN.HIDE_MODAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TestModal;
|
||||||
3
src/components/test-modal/index.js
Normal file
3
src/components/test-modal/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import TestModal from './TestModal';
|
||||||
|
|
||||||
|
export default TestModal;
|
||||||
@ -4,57 +4,60 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|||||||
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/app.js',
|
entry: './src/app.js',
|
||||||
output: {
|
output: {
|
||||||
filename: 'main.js',
|
filename: 'script.js',
|
||||||
path: path.resolve(__dirname, 'dist'),
|
path: path.resolve(__dirname, 'dist'),
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
compress: true,
|
compress: true,
|
||||||
port: 9000,
|
port: 9000,
|
||||||
open: true
|
open: true
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new CleanWebpackPlugin(),
|
new CleanWebpackPlugin(),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
template: './src/app.html'
|
template: './src/app.html'
|
||||||
}),
|
}),
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: 'style.css',
|
filename: 'style.css',
|
||||||
}),
|
}),
|
||||||
],
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.css$/i,
|
|
||||||
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
|
||||||
},
|
|
||||||
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"},
|
|
||||||
{
|
|
||||||
test: /\.(gif|png|jpe?g|svg)$/i,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'image-webpack-loader',
|
|
||||||
options: {
|
|
||||||
|
|
||||||
quality: 80
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 200000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
|
||||||
use: [
|
|
||||||
'file-loader',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
loader: "babel-loader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(gif|png|jpe?g|svg)$/i,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'image-webpack-loader',
|
||||||
|
options: {
|
||||||
|
quality: 80
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 200000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||||
|
use: [
|
||||||
|
'file-loader',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user