diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/dist/index.html b/dist/index.html new file mode 100755 index 0000000..462ebf4 --- /dev/null +++ b/dist/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + +To-Do List + + +
+
+ +
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/dist/main.js b/dist/main.js new file mode 100755 index 0000000..5509104 --- /dev/null +++ b/dist/main.js @@ -0,0 +1,146 @@ +/* + * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/domifier.js": +/*!*************************!*\ + !*** ./src/domifier.js ***! + \*************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"changeCurrentProject\": () => (/* binding */ changeCurrentProject),\n/* harmony export */ \"createProjectDOM\": () => (/* binding */ createProjectDOM),\n/* harmony export */ \"createTodo\": () => (/* binding */ createTodo),\n/* harmony export */ \"displayTodo\": () => (/* binding */ displayTodo),\n/* harmony export */ \"editTodo\": () => (/* binding */ editTodo),\n/* harmony export */ \"initDOM\": () => (/* binding */ initDOM)\n/* harmony export */ });\n/* harmony import */ var _todo_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./todo.js */ \"./src/todo.js\");\n/* harmony import */ var _project_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./project.js */ \"./src/project.js\");\n/* harmony import */ var _projects_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./projects.js */ \"./src/projects.js\");\n\n\n\n\nconst CURRENTPROJECT = document.getElementById(\"dropdownMenuButton1\");\n\n// shim for setting proper prototype when pulling from JSON\nconst PROJECT = (0,_project_js__WEBPACK_IMPORTED_MODULE_1__.project)(\"shim\");\n\n// initializes certain dom objects\nconst initDOM = () => {\n // creates New Todo button\n const newTodo = document.createElement(\"button\");\n newTodo.className = \"btn btn-warning\";\n newTodo.textContent = \"+ New Todo\";\n // event handlers\n newTodo.onclick = () => createTodo();\n // appends\n document.querySelector(\".nav-pills\").appendChild(newTodo)\n\n // creates New Project button\n const newProject = document.createElement(\"button\");\n newProject.className = \"btn btn-success\";\n newProject.textContent = \"+ New Project\";\n // event handlers\n newProject.onclick = () => {\n // asks for a project name\n const projectName = prompt(\"What will your new project be called?\", \"Default Project\");\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n // checks for blanks or default values\n if (projectName === null || projectName === \"\" || projectName === \"Default Project\") {\n alert(\"Please enter a valid project name\");\n }\n\n // checks if any projects are named the same way\n else if (dummyProjects.find (item => item.name === projectName)) {\n alert(\"Please enter an unused project name\");\n }\n // if valid, create new project\n else {\n createProject(projectName);\n }\n }\n // appends\n document.querySelector(\".nav-pills\").appendChild(newProject)\n\n // creates Delete Project button\n const delProject = document.createElement(\"button\");\n delProject.className = \"btn btn-danger\";\n delProject.textContent = \"x Delete Project\";\n // event handlers\n delProject.onclick = () => deleteProject();\n // appends\n document.querySelector(\".nav-pills\").appendChild(delProject);\n\n displayProjects();\n}\n\nconst changeCurrentProject = projectName => {\n // changes dropdown button to main project\n CURRENTPROJECT.textContent = projectName;\n // clears the board\n document.querySelector(\"main\").innerHTML = \"\";\n // finds all todos in the project and displays them (if any)\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n const projectInArray = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent);\n if (projectInArray.todos.length > -1) {\n projectInArray.todos.forEach(todo => displayTodo(todo));\n }\n}\n\nconst displayTodo = todo => {\n // sets up the necessary containers\n const card = document.createElement('div');\n card.className = \"card\";\n const cardBody = document.createElement('div');\n cardBody.className = \"card-body\";\n // appends title of current todo to DOM\n const title = document.createElement('h5');\n title.className = \"card-title mb-2\";\n title.textContent = todo.title;\n const dueDate = document.createElement('h6');\n dueDate.className = \"card-subtitle text-muted mb-1\";\n // bit of a rigamarole due to localStorage\n const date = new Date(Date.parse(todo.dueDate));\n dueDate.textContent = \"Due: \" + date.toDateString();\n //\n const priority = document.createElement('h6');\n priority.className = \"mb-3 btn prioritybtn\";\n const determinePriority = () => {\n if (todo.priority === 0) {\n priority.className = priority.className + \" btn-success\";\n priority.textContent = \"Low\";\n }\n else if (todo.priority == 1) {\n priority.className = priority.className + \" btn-warning\";\n priority.textContent = \"Medium\";\n }\n else if (todo.priority == 2) {\n priority.className = priority.className + \" btn-danger\";\n priority.textContent = \"High\";\n }\n return priority;\n }\n priority.textContent = \"Priority: \" + determinePriority().textContent;\n\n const comment = document.createElement('p');\n comment.className = \"card-text text-muted\";\n comment.textContent = todo.description;\n\n const editButton = document.createElement('button');\n editButton.className = \"btn btn-primary me-1\";\n const editButtonText = document.createElement('div');\n editButtonText.textContent = \"Edit\";\n editButton.onclick = () => editTodo(cardBody, todo);\n\n const deleteButton = document.createElement('button');\n deleteButton.className = \"btn btn-danger ms-1\";\n const deleteButtonText = document.createElement('div');\n deleteButtonText.textContent = \"Delete\";\n deleteButton.onclick = () => deleteTodo(todo, card);\n\n // append to DOM\n document.querySelector(\"main\").appendChild(card);\n card.appendChild(cardBody);\n cardBody.appendChild(title);\n cardBody.appendChild(dueDate);\n cardBody.appendChild(priority);\n cardBody.appendChild(comment);\n cardBody.appendChild(editButton);\n editButton.appendChild(editButtonText);\n cardBody.appendChild(deleteButton);\n deleteButton.appendChild(deleteButtonText);\n}\n\nconst deleteProject = () => {\n // removes the todos from the project\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n const projectInArray = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent);\n projectInArray.todos = [];\n \n // finds the current project in the dropdown menu\n // gets array of dropdown objects in dom and casts it to a \"real\" array;\n const dropdownArray = Array.prototype.slice.call(document.getElementsByClassName(\"dropdown-item\"));\n // finds the project which matches current project\n const currentProjectDropdown = dropdownArray.find(element => element.textContent === CURRENTPROJECT.textContent);\n // finds the next project\n const nextProjectDropdown = dropdownArray[dropdownArray.indexOf(currentProjectDropdown) + 1];\n const prevProjectDropdown = dropdownArray[dropdownArray.indexOf(currentProjectDropdown) - 1];\n\n // removes the current project from dropdowns\n const li = currentProjectDropdown.parentElement;\n li.parentElement.removeChild(li);\n\n // removes from projects array\n const projectNumber = dummyProjects.indexOf(projectInArray);\n dummyProjects.splice(projectNumber, 1);\n (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.setArray)(dummyProjects);\n\n // changes current project\n if (nextProjectDropdown) {\n changeCurrentProject(nextProjectDropdown.textContent);\n }\n else if (prevProjectDropdown) {\n changeCurrentProject(prevProjectDropdown.textContent);\n }\n else {\n CURRENTPROJECT.textContent = \"\";\n }\n}\n\nconst createProjectDOM = projectName => {\n // adds to dropdown\n const li = document.createElement(\"li\");\n document.querySelector(\".dropdown-menu\").appendChild(li);\n const dropdownOption = document.createElement(\"a\");\n dropdownOption.className = \"dropdown-item\";\n dropdownOption.textContent = projectName;\n li.appendChild(dropdownOption);\n // event handler for when user clicks the project in dropdowns\n li.onclick = () => changeCurrentProject(projectName);\n\n // changes to new project\n changeCurrentProject(projectName);\n}\n\nconst createTodo = () => {\n // sets up the necessary containers\n const card = document.createElement('div');\n card.className = \"card\";\n const cardBody = document.createElement('div');\n cardBody.className = \"card-body\";\n\n // creates input fields to get user input for todo info\n const title = document.createElement('input');\n title.className = \"card-title mb-2 form-control\";\n title.type = \"text\";\n title.placeholder = \"Title\";\n\n const dueDate = document.createElement('input');\n dueDate.className = \"card-subtitle text-muted mb-2 form-control\";\n dueDate.type = \"date\";\n dueDate.oninput = () => {\n const dueDateSplit = dueDate.value.split('-'); \n if (dueDateSplit[0] && dueDateSplit[0].length > 4) { \n dueDateSplit[0]=dueDateSplit[0].slice(0,4); \n dueDate.value = dueDateSplit.join('-');\n }\n }\n const priority = document.createElement('h6');\n const oldClassName = \"mb-3 btn btn-primary\";\n priority.className = oldClassName;\n priority.textContent = \"Priority\"\n let priorityLevel;\n let counter = 0;\n priority.onclick = () => {\n if (counter === 0) {\n priority.className = oldClassName + \" btn-success\";\n priority.textContent = \"Priority: Low\";\n priorityLevel = counter;\n counter++;\n }\n else if (counter === 1) {\n priority.className = oldClassName + \" btn-warning\";\n priority.textContent = \"Priority: Medium\";\n priorityLevel = counter;\n counter++;\n }\n else {\n priority.className = oldClassName + \" btn-danger\";\n priority.textContent = \"Priority: High\";\n priorityLevel = counter;\n counter = 0;\n }\n }\n\n const comment = document.createElement('input');\n comment.className = \"card-text text-muted form-control mb-3\";\n comment.type = \"text\";\n comment.placeholder = \"Description\"\n\n const createButton = document.createElement('button');\n createButton.className = \"btn btn-success me-1\";\n const createButtonText = document.createElement('div');\n createButtonText.textContent = \"Create\";\n createButton.onclick = () => finalizeTodo();\n\n const deleteButton = document.createElement('button');\n deleteButton.className = \"btn btn-danger ms-1\";\n const deleteButtonText = document.createElement('div');\n deleteButtonText.textContent = \"Cancel\";\n\n deleteButton.onclick = () => document.querySelector(\"main\").removeChild(card);\n\n document.querySelector('main').appendChild(card);\n card.appendChild(cardBody);\n cardBody.appendChild(title);\n cardBody.appendChild(dueDate);\n cardBody.appendChild(priority);\n cardBody.appendChild(comment);\n cardBody.appendChild(createButton);\n createButton.appendChild(createButtonText);\n cardBody.appendChild(deleteButton);\n deleteButton.appendChild(deleteButtonText);\n\n function finalizeTodo() {\n // some validation\n if (title.value === \"Title\" || title.value === \"\") {\n alert(\"Please enter a name for your to-do\");\n }\n else {\n if (priorityLevel || priorityLevel === 0) {\n // adds todo to project\n const finalizedTodo = (0,_todo_js__WEBPACK_IMPORTED_MODULE_0__.todo)(title.value, comment.value, dueDate.valueAsDate, priorityLevel);\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n let foundProject = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent);\n\n foundProject.todos[foundProject.todos.length] = finalizedTodo;\n (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.setArray)(dummyProjects);\n \n // wipes prompt window\n document.querySelector(\"main\").removeChild(card);\n displayTodo(finalizedTodo);\n }\n else {\n alert(\"Please select a priority for your to-do by clicking the Priority button\");\n }\n }\n }\n}\n\nconst editTodo = (cardBody, todo) => {\n // creates title field and fills with existing title\n const title = document.createElement('input');\n title.className = \"card-title mb-2 form-control\";\n title.type = \"text\";\n // gets title out of existing title (title is the first child of cardBody)\n title.value = cardBody.firstChild.textContent;\n\n \n const dueDate = document.createElement('input');\n dueDate.maxLength = 8;\n dueDate.className = \"card-subtitle text-muted mb-2 form-control\";\n dueDate.type = \"date\";\n if (typeof todo.dueDate === \"object\") {\n dueDate.value = todo.dueDate.toISOString().slice(0,10);\n }\n else {\n dueDate.value = todo.dueDate.slice(0,10);\n }\n dueDate.oninput = () => {\n const dueDateSplit = dueDate.value.split('-'); \n if (dueDateSplit[0] && dueDateSplit[0].length > 4) { \n dueDateSplit[0]=dueDateSplit[0].slice(0,4); \n dueDate.value = dueDateSplit.join('-');\n }\n }\n \n const priority = document.createElement('h6');\n const oldClassName = \"mb-3 btn btn-primary\";\n priority.className = oldClassName;\n priority.textContent = \"Priority\";\n let counter;\n let priorityLevel = todo.priority;\n if (todo.priority === 0) {\n priority.className = oldClassName + \" btn-success\";\n priority.textContent = \"Priority: Low\";\n counter = 1;\n }\n else if (todo.priority === 1) {\n priority.className = oldClassName + \" btn-warning\";\n priority.textContent = \"Priority: Medium\";\n counter = 2;\n }\n else {\n priority.className = oldClassName + \" btn-danger\";\n priority.textContent = \"Priority: High\";\n counter = 0;\n }\n\n priority.onclick = () => {\n if (counter === 0) {\n priority.className = oldClassName + \" btn-success\";\n priority.textContent = \"Priority: Low\";\n priorityLevel = counter;\n counter++;\n }\n else if (counter === 1) {\n priority.className = oldClassName + \" btn-warning\";\n priority.textContent = \"Priority: Medium\";\n priorityLevel = counter;\n counter++;\n }\n else {\n priority.className = oldClassName + \" btn-danger\";\n priority.textContent = \"Priority: High\";\n priorityLevel = counter;\n counter = 0;\n }\n }\n\n const comment = document.createElement('input');\n comment.className = \"card-text text-muted form-control mb-3\";\n comment.type = \"text\";\n comment.value = cardBody.children[3].textContent;\n\n for (let i = 0; i < 4; i++) {\n cardBody.removeChild(cardBody.firstChild);\n }\n\n cardBody.firstChild.textContent = \"Finish\";\n cardBody.firstChild.className = \"btn btn-success me-1\";\n cardBody.firstChild.onclick = () => finalizeTodo();\n\n cardBody.prepend(comment);\n cardBody.prepend(priority);\n cardBody.prepend(dueDate);\n cardBody.prepend(title);\n\n function finalizeTodo() {\n // some validation\n if (title.value === \"\") {\n alert(\"Please enter a name for your to-do\");\n }\n else {\n if (priorityLevel || priorityLevel === 0) {\n todo.title = title.value;\n todo.description = comment.value;\n todo.dueDate = dueDate.valueAsDate;\n todo.priority = priorityLevel;\n \n // proper handling\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n const foundProject = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent);\n (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.setArray)(dummyProjects);\n \n // wipes prompt window\n document.querySelector(\"main\").removeChild(cardBody.parentElement);\n displayTodo(todo);\n }\n else {\n alert(\"Please select a priority for your to-do by clicking the Priority button\")\n }\n }\n }\n}\n\nconst deleteTodo = (todo, card) => {\n document.querySelector(\"main\").removeChild(card);\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n let foundProject = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent);\n const todoIndex = foundProject.todos.indexOf(todo);\n if (todoIndex) {\n foundProject.todos.splice(todoIndex, 1);\n }\n (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.setArray)(dummyProjects);\n}\n\nconst createProject = (projectName) => {\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n dummyProjects[dummyProjects.length] = (0,_project_js__WEBPACK_IMPORTED_MODULE_1__.project)(projectName);\n (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.setArray)(dummyProjects);\n createProjectDOM(projectName);\n}\n\nconst displayProjects = () => {\n const dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_2__.getArray)();\n dummyProjects.forEach(item => createProjectDOM(item.name));\n}\n\n//# sourceURL=webpack://js-todolist/./src/domifier.js?"); + +/***/ }), + +/***/ "./src/incrementer.js": +/*!****************************!*\ + !*** ./src/incrementer.js ***! + \****************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"incrementer\": () => (/* binding */ incrementer)\n/* harmony export */ });\n// increments date based from today's date on number of days specified\nconst incrementer = (date, days) => {\n date.setDate(date.getDate() + days);\n return date;\n}\n\n//# sourceURL=webpack://js-todolist/./src/incrementer.js?"); + +/***/ }), + +/***/ "./src/index.js": +/*!**********************!*\ + !*** ./src/index.js ***! + \**********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _todo_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./todo.js */ \"./src/todo.js\");\n/* harmony import */ var _incrementer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./incrementer.js */ \"./src/incrementer.js\");\n/* harmony import */ var _domifier_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./domifier.js */ \"./src/domifier.js\");\n/* harmony import */ var _projects_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./projects.js */ \"./src/projects.js\");\n/* harmony import */ var _project_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./project.js */ \"./src/project.js\");\n\n\n\n\n\n\n\nconst TODAY = new Date();\nlet dummyProjects = (0,_projects_js__WEBPACK_IMPORTED_MODULE_3__.getArray)();\n\ndummyProjects[0] = (0,_project_js__WEBPACK_IMPORTED_MODULE_4__.project)(\"Default Project\");\n\nconst defaultTodo = (0,_todo_js__WEBPACK_IMPORTED_MODULE_0__.todo)(\n \"Default Todo\", \n \"This is the default to-do for the to-do list. Feel free to add some more!\", \n (0,_incrementer_js__WEBPACK_IMPORTED_MODULE_1__.incrementer)(TODAY, 7),\n 0\n);\n\n\ndummyProjects[0].todos[dummyProjects[0].todos.length] = defaultTodo;\n(0,_projects_js__WEBPACK_IMPORTED_MODULE_3__.setArray)(dummyProjects);\n\n(0,_domifier_js__WEBPACK_IMPORTED_MODULE_2__.initDOM)();\n(0,_domifier_js__WEBPACK_IMPORTED_MODULE_2__.changeCurrentProject)(dummyProjects[0].name);\n\n//# sourceURL=webpack://js-todolist/./src/index.js?"); + +/***/ }), + +/***/ "./src/project.js": +/*!************************!*\ + !*** ./src/project.js ***! + \************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"project\": () => (/* binding */ project)\n/* harmony export */ });\nconst project = (name) => {\r\n // sets up array of todo objects\r\n let todos = []\r\n \r\n return {\r\n name,\r\n todos\r\n }\r\n}\n\n//# sourceURL=webpack://js-todolist/./src/project.js?"); + +/***/ }), + +/***/ "./src/projects.js": +/*!*************************!*\ + !*** ./src/projects.js ***! + \*************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"getArray\": () => (/* binding */ getArray),\n/* harmony export */ \"setArray\": () => (/* binding */ setArray)\n/* harmony export */ });\n/* harmony import */ var _storageAvailable_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./storageAvailable.js */ \"./src/storageAvailable.js\");\n// logic for the projects array itself\n\n\n// get and set arrays - get from local storage if available, if not then get from a global var\n// set it here too, as well as extend the regular array methods\n// everything will be here regards getting and setting this stuff, without a need to expose the actual array out to other modules\n\n// master projects array\nlet projectsArray = [];\n\n// tests if a \"projects\" item exists in local storage\nconst projectsExists = localStorage.getItem(\"projects\") ? true : false;\n\n// returns the proper array depending on where it is\nconst getArray = () => {\n // localStorage exists\n if (_storageAvailable_js__WEBPACK_IMPORTED_MODULE_0__.storageAvailable) {\n // \"projects\" exists\n if (projectsExists) {\n // set projects array to local storage and return\n projectsArray = JSON.parse(localStorage.projects);\n return projectsArray;\n }\n else {\n return projectsArray;\n }\n }\n // otherwise return the projects array here\n else {\n return projectsArray;\n }\n}\n\n// easiest workaround to getting too in-depth - passed array is set as the main, depending on if storage exists, etc.\nconst setArray = (array) => {\n // set the master array to passed array - regardless of localStorage\n projectsArray = array;\n // check for localStorage\n if (_storageAvailable_js__WEBPACK_IMPORTED_MODULE_0__.storageAvailable) {\n // and existing \"projects\"\n if (projectsExists) {\n // remove existing array from localStorage\n localStorage.removeItem(\"projects\");\n // add the modified array\n localStorage.projects = JSON.stringify(projectsArray);\n }\n // if \"projects\" doesn't exist, add it\n else {\n localStorage.projects = JSON.stringify(projectsArray);\n }\n }\n}\n\n//# sourceURL=webpack://js-todolist/./src/projects.js?"); + +/***/ }), + +/***/ "./src/storageAvailable.js": +/*!*********************************!*\ + !*** ./src/storageAvailable.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"storageAvailable\": () => (/* binding */ storageAvailable)\n/* harmony export */ });\nfunction storageAvailableFunc(type) {\n let storage;\n try {\n storage = window[type];\n const x = \"__storage_test__\";\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return (\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === \"QuotaExceededError\" ||\n // Firefox\n e.name === \"NS_ERROR_DOM_QUOTA_REACHED\") &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n// copyright MDN https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API\n\nconst storageAvailable = storageAvailableFunc(\"localStorage\");\n\n//# sourceURL=webpack://js-todolist/./src/storageAvailable.js?"); + +/***/ }), + +/***/ "./src/todo.js": +/*!*********************!*\ + !*** ./src/todo.js ***! + \*********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"todo\": () => (/* binding */ todo)\n/* harmony export */ });\n// todo factory function\r\nconst todo = (title, description, dueDate, priority) => {\r\n return {\r\n title,\r\n description,\r\n dueDate,\r\n priority\r\n }\r\n}\n\n//# sourceURL=webpack://js-todolist/./src/todo.js?"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./src/index.js"); +/******/ +/******/ })() +; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100755 index 0000000..b2b0ed2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1331 @@ +{ + "name": "js-todolist", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "js-todolist", + "version": "1.0.0", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "webpack": "^5.77.0", + "webpack-cli": "^5.0.1" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@types/eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001473", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz", + "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.349", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.349.tgz", + "integrity": "sha512-34LBfVDiL6byWorSmQOPwq4gD5wpN8Mhh5yPGQr67FbcxsfUS0BDJP9y6RykSgeWVUfSkN/2dChywnsrmKVyUg==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.16.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz", + "integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100755 index 0000000..3a0606d --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "js-todolist", + "version": "1.0.0", + "description": "to-do list implemented in ES6", + "main": "js/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" + }, + "keywords": [ + "js", + "javascript", + "odin", + "todo", + "list" + ], + "author": "ak", + "license": "AGPL-3.0-or-later", + "devDependencies": { + "webpack": "^5.77.0", + "webpack-cli": "^5.0.1" + } +} diff --git a/src/domifier.js b/src/domifier.js new file mode 100755 index 0000000..fbae5ca --- /dev/null +++ b/src/domifier.js @@ -0,0 +1,429 @@ +import { todo } from "./todo.js"; +import { project } from "./project.js"; +import { getArray, setArray } from "./projects.js" + +const CURRENTPROJECT = document.getElementById("dropdownMenuButton1"); + +// shim for setting proper prototype when pulling from JSON +const PROJECT = project("shim"); + +// initializes certain dom objects +export const initDOM = () => { + // creates New Todo button + const newTodo = document.createElement("button"); + newTodo.className = "btn btn-warning"; + newTodo.textContent = "+ New Todo"; + // event handlers + newTodo.onclick = () => createTodo(); + // appends + document.querySelector(".nav-pills").appendChild(newTodo) + + // creates New Project button + const newProject = document.createElement("button"); + newProject.className = "btn btn-success"; + newProject.textContent = "+ New Project"; + // event handlers + newProject.onclick = () => { + // asks for a project name + const projectName = prompt("What will your new project be called?", "Default Project"); + const dummyProjects = getArray(); + // checks for blanks or default values + if (projectName === null || projectName === "" || projectName === "Default Project") { + alert("Please enter a valid project name"); + } + + // checks if any projects are named the same way + else if (dummyProjects.find (item => item.name === projectName)) { + alert("Please enter an unused project name"); + } + // if valid, create new project + else { + createProject(projectName); + } + } + // appends + document.querySelector(".nav-pills").appendChild(newProject) + + // creates Delete Project button + const delProject = document.createElement("button"); + delProject.className = "btn btn-danger"; + delProject.textContent = "x Delete Project"; + // event handlers + delProject.onclick = () => deleteProject(); + // appends + document.querySelector(".nav-pills").appendChild(delProject); + + displayProjects(); +} + +export const changeCurrentProject = projectName => { + // changes dropdown button to main project + CURRENTPROJECT.textContent = projectName; + // clears the board + document.querySelector("main").innerHTML = ""; + // finds all todos in the project and displays them (if any) + const dummyProjects = getArray(); + const projectInArray = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent); + if (projectInArray.todos.length > -1) { + projectInArray.todos.forEach(todo => displayTodo(todo)); + } +} + +export const displayTodo = todo => { + // sets up the necessary containers + const card = document.createElement('div'); + card.className = "card"; + const cardBody = document.createElement('div'); + cardBody.className = "card-body"; + // appends title of current todo to DOM + const title = document.createElement('h5'); + title.className = "card-title mb-2"; + title.textContent = todo.title; + const dueDate = document.createElement('h6'); + dueDate.className = "card-subtitle text-muted mb-1"; + // bit of a rigamarole due to localStorage + const date = new Date(Date.parse(todo.dueDate)); + dueDate.textContent = "Due: " + date.toDateString(); + // + const priority = document.createElement('h6'); + priority.className = "mb-3 btn prioritybtn"; + const determinePriority = () => { + if (todo.priority === 0) { + priority.className = priority.className + " btn-success"; + priority.textContent = "Low"; + } + else if (todo.priority == 1) { + priority.className = priority.className + " btn-warning"; + priority.textContent = "Medium"; + } + else if (todo.priority == 2) { + priority.className = priority.className + " btn-danger"; + priority.textContent = "High"; + } + return priority; + } + priority.textContent = "Priority: " + determinePriority().textContent; + + const comment = document.createElement('p'); + comment.className = "card-text text-muted"; + comment.textContent = todo.description; + + const editButton = document.createElement('button'); + editButton.className = "btn btn-primary me-1"; + const editButtonText = document.createElement('div'); + editButtonText.textContent = "Edit"; + editButton.onclick = () => editTodo(cardBody, todo); + + const deleteButton = document.createElement('button'); + deleteButton.className = "btn btn-danger ms-1"; + const deleteButtonText = document.createElement('div'); + deleteButtonText.textContent = "Delete"; + deleteButton.onclick = () => deleteTodo(todo, card); + + // append to DOM + document.querySelector("main").appendChild(card); + card.appendChild(cardBody); + cardBody.appendChild(title); + cardBody.appendChild(dueDate); + cardBody.appendChild(priority); + cardBody.appendChild(comment); + cardBody.appendChild(editButton); + editButton.appendChild(editButtonText); + cardBody.appendChild(deleteButton); + deleteButton.appendChild(deleteButtonText); +} + +const deleteProject = () => { + // removes the todos from the project + const dummyProjects = getArray(); + const projectInArray = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent); + projectInArray.todos = []; + + // finds the current project in the dropdown menu + // gets array of dropdown objects in dom and casts it to a "real" array; + const dropdownArray = Array.prototype.slice.call(document.getElementsByClassName("dropdown-item")); + // finds the project which matches current project + const currentProjectDropdown = dropdownArray.find(element => element.textContent === CURRENTPROJECT.textContent); + // finds the next project + const nextProjectDropdown = dropdownArray[dropdownArray.indexOf(currentProjectDropdown) + 1]; + const prevProjectDropdown = dropdownArray[dropdownArray.indexOf(currentProjectDropdown) - 1]; + + // removes the current project from dropdowns + const li = currentProjectDropdown.parentElement; + li.parentElement.removeChild(li); + + // removes from projects array + const projectNumber = dummyProjects.indexOf(projectInArray); + dummyProjects.splice(projectNumber, 1); + setArray(dummyProjects); + + // changes current project + if (nextProjectDropdown) { + changeCurrentProject(nextProjectDropdown.textContent); + } + else if (prevProjectDropdown) { + changeCurrentProject(prevProjectDropdown.textContent); + } + else { + CURRENTPROJECT.textContent = ""; + } +} + +export const createProjectDOM = projectName => { + // adds to dropdown + const li = document.createElement("li"); + document.querySelector(".dropdown-menu").appendChild(li); + const dropdownOption = document.createElement("a"); + dropdownOption.className = "dropdown-item"; + dropdownOption.textContent = projectName; + li.appendChild(dropdownOption); + // event handler for when user clicks the project in dropdowns + li.onclick = () => changeCurrentProject(projectName); + + // changes to new project + changeCurrentProject(projectName); +} + +export const createTodo = () => { + // sets up the necessary containers + const card = document.createElement('div'); + card.className = "card"; + const cardBody = document.createElement('div'); + cardBody.className = "card-body"; + + // creates input fields to get user input for todo info + const title = document.createElement('input'); + title.className = "card-title mb-2 form-control"; + title.type = "text"; + title.placeholder = "Title"; + + const dueDate = document.createElement('input'); + dueDate.className = "card-subtitle text-muted mb-2 form-control"; + dueDate.type = "date"; + dueDate.oninput = () => { + const dueDateSplit = dueDate.value.split('-'); + if (dueDateSplit[0] && dueDateSplit[0].length > 4) { + dueDateSplit[0]=dueDateSplit[0].slice(0,4); + dueDate.value = dueDateSplit.join('-'); + } + } + const priority = document.createElement('h6'); + const oldClassName = "mb-3 btn btn-primary"; + priority.className = oldClassName; + priority.textContent = "Priority" + let priorityLevel; + let counter = 0; + priority.onclick = () => { + if (counter === 0) { + priority.className = oldClassName + " btn-success"; + priority.textContent = "Priority: Low"; + priorityLevel = counter; + counter++; + } + else if (counter === 1) { + priority.className = oldClassName + " btn-warning"; + priority.textContent = "Priority: Medium"; + priorityLevel = counter; + counter++; + } + else { + priority.className = oldClassName + " btn-danger"; + priority.textContent = "Priority: High"; + priorityLevel = counter; + counter = 0; + } + } + + const comment = document.createElement('input'); + comment.className = "card-text text-muted form-control mb-3"; + comment.type = "text"; + comment.placeholder = "Description" + + const createButton = document.createElement('button'); + createButton.className = "btn btn-success me-1"; + const createButtonText = document.createElement('div'); + createButtonText.textContent = "Create"; + createButton.onclick = () => finalizeTodo(); + + const deleteButton = document.createElement('button'); + deleteButton.className = "btn btn-danger ms-1"; + const deleteButtonText = document.createElement('div'); + deleteButtonText.textContent = "Cancel"; + + deleteButton.onclick = () => document.querySelector("main").removeChild(card); + + document.querySelector('main').appendChild(card); + card.appendChild(cardBody); + cardBody.appendChild(title); + cardBody.appendChild(dueDate); + cardBody.appendChild(priority); + cardBody.appendChild(comment); + cardBody.appendChild(createButton); + createButton.appendChild(createButtonText); + cardBody.appendChild(deleteButton); + deleteButton.appendChild(deleteButtonText); + + function finalizeTodo() { + // some validation + if (title.value === "Title" || title.value === "") { + alert("Please enter a name for your to-do"); + } + else { + if (priorityLevel || priorityLevel === 0) { + // adds todo to project + const finalizedTodo = todo(title.value, comment.value, dueDate.valueAsDate, priorityLevel); + const dummyProjects = getArray(); + let foundProject = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent); + + foundProject.todos[foundProject.todos.length] = finalizedTodo; + setArray(dummyProjects); + + // wipes prompt window + document.querySelector("main").removeChild(card); + displayTodo(finalizedTodo); + } + else { + alert("Please select a priority for your to-do by clicking the Priority button"); + } + } + } +} + +export const editTodo = (cardBody, todo) => { + // creates title field and fills with existing title + const title = document.createElement('input'); + title.className = "card-title mb-2 form-control"; + title.type = "text"; + // gets title out of existing title (title is the first child of cardBody) + title.value = cardBody.firstChild.textContent; + + + const dueDate = document.createElement('input'); + dueDate.maxLength = 8; + dueDate.className = "card-subtitle text-muted mb-2 form-control"; + dueDate.type = "date"; + if (typeof todo.dueDate === "object") { + dueDate.value = todo.dueDate.toISOString().slice(0,10); + } + else { + dueDate.value = todo.dueDate.slice(0,10); + } + dueDate.oninput = () => { + const dueDateSplit = dueDate.value.split('-'); + if (dueDateSplit[0] && dueDateSplit[0].length > 4) { + dueDateSplit[0]=dueDateSplit[0].slice(0,4); + dueDate.value = dueDateSplit.join('-'); + } + } + + const priority = document.createElement('h6'); + const oldClassName = "mb-3 btn btn-primary"; + priority.className = oldClassName; + priority.textContent = "Priority"; + let counter; + let priorityLevel = todo.priority; + if (todo.priority === 0) { + priority.className = oldClassName + " btn-success"; + priority.textContent = "Priority: Low"; + counter = 1; + } + else if (todo.priority === 1) { + priority.className = oldClassName + " btn-warning"; + priority.textContent = "Priority: Medium"; + counter = 2; + } + else { + priority.className = oldClassName + " btn-danger"; + priority.textContent = "Priority: High"; + counter = 0; + } + + priority.onclick = () => { + if (counter === 0) { + priority.className = oldClassName + " btn-success"; + priority.textContent = "Priority: Low"; + priorityLevel = counter; + counter++; + } + else if (counter === 1) { + priority.className = oldClassName + " btn-warning"; + priority.textContent = "Priority: Medium"; + priorityLevel = counter; + counter++; + } + else { + priority.className = oldClassName + " btn-danger"; + priority.textContent = "Priority: High"; + priorityLevel = counter; + counter = 0; + } + } + + const comment = document.createElement('input'); + comment.className = "card-text text-muted form-control mb-3"; + comment.type = "text"; + comment.value = cardBody.children[3].textContent; + + for (let i = 0; i < 4; i++) { + cardBody.removeChild(cardBody.firstChild); + } + + cardBody.firstChild.textContent = "Finish"; + cardBody.firstChild.className = "btn btn-success me-1"; + cardBody.firstChild.onclick = () => finalizeTodo(); + + cardBody.prepend(comment); + cardBody.prepend(priority); + cardBody.prepend(dueDate); + cardBody.prepend(title); + + function finalizeTodo() { + // some validation + if (title.value === "") { + alert("Please enter a name for your to-do"); + } + else { + if (priorityLevel || priorityLevel === 0) { + todo.title = title.value; + todo.description = comment.value; + todo.dueDate = dueDate.valueAsDate; + todo.priority = priorityLevel; + + // proper handling + const dummyProjects = getArray(); + const foundProject = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent); + setArray(dummyProjects); + + // wipes prompt window + document.querySelector("main").removeChild(cardBody.parentElement); + displayTodo(todo); + } + else { + alert("Please select a priority for your to-do by clicking the Priority button") + } + } + } +} + +const deleteTodo = (todo, card) => { + document.querySelector("main").removeChild(card); + const dummyProjects = getArray(); + let foundProject = dummyProjects.find (item => item.name === CURRENTPROJECT.textContent); + const todoIndex = foundProject.todos.indexOf(todo); + if (todoIndex) { + foundProject.todos.splice(todoIndex, 1); + } + setArray(dummyProjects); +} + +const createProject = (projectName) => { + const dummyProjects = getArray(); + dummyProjects[dummyProjects.length] = project(projectName); + setArray(dummyProjects); + createProjectDOM(projectName); +} + +const displayProjects = () => { + const dummyProjects = getArray(); + dummyProjects.forEach(item => createProjectDOM(item.name)); +} \ No newline at end of file diff --git a/src/incrementer.js b/src/incrementer.js new file mode 100755 index 0000000..f82184b --- /dev/null +++ b/src/incrementer.js @@ -0,0 +1,5 @@ +// increments date based from today's date on number of days specified +export const incrementer = (date, days) => { + date.setDate(date.getDate() + days); + return date; +} \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100755 index 0000000..55d9acc --- /dev/null +++ b/src/index.js @@ -0,0 +1,25 @@ +import { todo } from "./todo.js" +import { incrementer } from "./incrementer.js"; +import { changeCurrentProject, createProjectDOM } from "./domifier.js"; +import { initDOM } from "./domifier.js"; +import { getArray, setArray } from "./projects.js"; +import { project } from "./project.js"; + +const TODAY = new Date(); +let dummyProjects = getArray(); + +dummyProjects[0] = project("Default Project"); + +const defaultTodo = todo( + "Default Todo", + "This is the default to-do for the to-do list. Feel free to add some more!", + incrementer(TODAY, 7), + 0 +); + + +dummyProjects[0].todos[dummyProjects[0].todos.length] = defaultTodo; +setArray(dummyProjects); + +initDOM(); +changeCurrentProject(dummyProjects[0].name); \ No newline at end of file diff --git a/src/project.js b/src/project.js new file mode 100755 index 0000000..46acd20 --- /dev/null +++ b/src/project.js @@ -0,0 +1,9 @@ +export const project = (name) => { + // sets up array of todo objects + let todos = [] + + return { + name, + todos + } +} \ No newline at end of file diff --git a/src/projects.js b/src/projects.js new file mode 100755 index 0000000..72028f9 --- /dev/null +++ b/src/projects.js @@ -0,0 +1,52 @@ +// logic for the projects array itself +import { storageAvailable } from "./storageAvailable.js"; + +// get and set arrays - get from local storage if available, if not then get from a global var +// set it here too, as well as extend the regular array methods +// everything will be here regards getting and setting this stuff, without a need to expose the actual array out to other modules + +// master projects array +let projectsArray = []; + +// tests if a "projects" item exists in local storage +const projectsExists = localStorage.getItem("projects") ? true : false; + +// returns the proper array depending on where it is +export const getArray = () => { + // localStorage exists + if (storageAvailable) { + // "projects" exists + if (projectsExists) { + // set projects array to local storage and return + projectsArray = JSON.parse(localStorage.projects); + return projectsArray; + } + else { + return projectsArray; + } + } + // otherwise return the projects array here + else { + return projectsArray; + } +} + +// easiest workaround to getting too in-depth - passed array is set as the main, depending on if storage exists, etc. +export const setArray = (array) => { + // set the master array to passed array - regardless of localStorage + projectsArray = array; + // check for localStorage + if (storageAvailable) { + // and existing "projects" + if (projectsExists) { + // remove existing array from localStorage + localStorage.removeItem("projects"); + // add the modified array + localStorage.projects = JSON.stringify(projectsArray); + } + // if "projects" doesn't exist, add it + else { + localStorage.projects = JSON.stringify(projectsArray); + } + } +} \ No newline at end of file diff --git a/src/storageAvailable.js b/src/storageAvailable.js new file mode 100755 index 0000000..81b01fb --- /dev/null +++ b/src/storageAvailable.js @@ -0,0 +1,29 @@ +function storageAvailableFunc(type) { + let storage; + try { + storage = window[type]; + const x = "__storage_test__"; + storage.setItem(x, x); + storage.removeItem(x); + return true; + } catch (e) { + return ( + e instanceof DOMException && + // everything except Firefox + (e.code === 22 || + // Firefox + e.code === 1014 || + // test name field too, because code might not be present + // everything except Firefox + e.name === "QuotaExceededError" || + // Firefox + e.name === "NS_ERROR_DOM_QUOTA_REACHED") && + // acknowledge QuotaExceededError only if there's something already stored + storage && + storage.length !== 0 + ); + } +} +// copyright MDN https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API + +export const storageAvailable = storageAvailableFunc("localStorage"); \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100755 index 0000000..600b41e --- /dev/null +++ b/src/style.css @@ -0,0 +1,45 @@ +.nav-pills { + gap: 1rem; +} + +.dropdown-toggle::after { + margin-left: .3em; + vertical-align: .15em; +} + +.card { + width: 18rem; +} + +.col-sm-6 { + flex: 1; + width: auto; +} + +.card { + box-shadow: 0.5px 0.5px 5px black; + margin: 0rem 1.5rem 1.5rem 0rem; + flex-grow: 0; + flex-shrink: 0; +} + +.prioritybtn { + cursor: default; +} + +main { + display: inline-flex; + flex-flow: row wrap; + overflow: scroll; + justify-content: flex-start +} + +/* hides scrollbar*/ +main::-webkit-scrollbar { + display: none; +} + +main { + -ms-overflow-style: none; + scrollbar-width: none; +} \ No newline at end of file diff --git a/src/todo.js b/src/todo.js new file mode 100755 index 0000000..338b17b --- /dev/null +++ b/src/todo.js @@ -0,0 +1,9 @@ +// todo factory function +export const todo = (title, description, dueDate, priority) => { + return { + title, + description, + dueDate, + priority + } +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100755 index 0000000..51ed023 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,3 @@ +module.exports = { + mode: 'development' +}; \ No newline at end of file