A Pen by Tim

Thumbnail
This awesome code was written by tevko, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright tevko ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>A Pen by  Tim</title>
  
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">

  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  
<section id="my-app"></section>
  
  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/tevko/a-pen-by-tim-MrwXdy */
* {
  box-sizing: border-box;
}

body {
  margin: 3em;
  background-color: #f3f3f3;
}

input {
  width: 320px;
  padding: 25px;
}

.posRel {
  position: relative;
}

.toggleAll {
  position: absolute;
  top: 50%;
  -webkit-transform: translateY(-50%) rotate(90deg);
          transform: translateY(-50%) rotate(90deg);
  left: 8px;
  cursor: pointer;
}

button {
  cursor: pointer;
}

.filter {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  background-color: white;
  border-top: solid 1px;
  padding: 10px;
}
.filter button {
  background-color: transparent;
  border: solid 1px;
  border-color: transparent;
}
.filter button.selected {
  border-color: #d6b2b2;
}

::-webkit-input-placeholder {
  color: #c1c1c1;
  font-style: italic;
}

.todo {
  max-width: 320px;
  margin: 0 auto;
}
.todo h1 {
  text-align: center;
  font-size: 2em;
  color: #d6b2b2;
}

.list-container {
  width: 100%;
}

.item {
  display: flex;
  align-items: center;
  margin-top: 0.5em;
  padding: 25px;
  padding-left: 30px;
  background-color: #ffffff;
  position: relative;
}
.item.itemChecked {
  text-decoration: line-through;
  color: #bdbdbd;
}
.item:hover svg {
  display: block;
}
.item svg {
  cursor: pointer;
  position: absolute;
  right: 25px;
  display: none;
  top: 50%;
  -webkit-transform: translateY(-50%);
          transform: translateY(-50%);
}

.check {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: solid 1px;
  position: absolute;
  left: 7px;
  cursor: pointer;
}
.check.isChecked {
  background-color: black;
}

.hidden {
  display: none;
}


/*Downloaded from https://www.codeseek.co/tevko/a-pen-by-tim-MrwXdy */
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

var vDiff = function vDiff(target, source) {
	var worker = {
		settings: {
			original: target
		},
		replace: function replace(target) {
			var source = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : target;

			var v = document.createElement('template');
			v.innerHTML = source;
			var vHTML = v.content.firstChild.nextElementSibling;
			if (vHTML.nodeName !== target.nodeName) {
				target.parentElement.replaceChild(vHTML, target);
				return;
			}
			this.iterate(target, vHTML);
		},
		iterate: function iterate(targetNode, sourceNode, tOriginal, sOriginal) {
			var _this = this;

			if (targetNode || sourceNode) {
				this.checkAdditions(targetNode, sourceNode, tOriginal, sOriginal);
				if (targetNode && sourceNode && targetNode.nodeName !== sourceNode.nodeName) {
					this.checkNodeName(targetNode, sourceNode);
				} else if (targetNode && sourceNode && targetNode.nodeName === sourceNode.nodeName) {
					this.checkTextContent(targetNode, sourceNode);
					targetNode.nodeType !== 3 && target.nodeType !== 8 && this.checkAttributes(targetNode, sourceNode);
				}
			}
			if (targetNode && sourceNode) {
				if (targetNode.childNodes && sourceNode.childNodes) {
					this.settings.lengthDifferentiator = [].concat(_toConsumableArray(target.childNodes), _toConsumableArray(sourceNode.childNodes));
				} else {
					this.settings.lengthDifferentiator = null;
				}
				Array.apply(null, this.settings.lengthDifferentiator).forEach(function (node, idx) {
					_this.settings.lengthDifferentiator && _this.iterate(targetNode.childNodes[idx], sourceNode.childNodes[idx], targetNode, sourceNode);
				});
			}
		},
		checkNodeName: function checkNodeName(targetNode, sourceNode) {
			var n = sourceNode.cloneNode(true);
			targetNode.parentElement.replaceChild(n, targetNode);
		},
		checkAttributes: function checkAttributes(targetNode, sourceNode) {
			var attributes = targetNode.attributes || [];
			var filteredAttrs = Object.keys(attributes).map(function (n) {
				return attributes[n];
			});
			var attributesNew = sourceNode.attributes || [];
			var filteredAttrsNew = Object.keys(attributesNew).map(function (n) {
				return attributesNew[n];
			});
			filteredAttrs.forEach(function (o) {
				return sourceNode.getAttribute(o.name) !== null ? targetNode.setAttribute(o.name, sourceNode.getAttribute(o.name)) : targetNode.removeAttribute(o.name);
			});
			filteredAttrsNew.forEach(function (a) {
				return targetNode.getAttribute(a.name) !== sourceNode.getAttribute(a.name) && targetNode.setAttribute(a.name, sourceNode.getAttribute(a.name));
			});
		},
		checkTextContent: function checkTextContent(targetNode, sourceNode) {
			if (targetNode.nodeValue !== sourceNode.nodeValue) {
				targetNode.textContent = sourceNode.textContent;
			}
		},
		checkAdditions: function checkAdditions(targetNode, sourceNode) {
			var tParent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.settings.original;
			var sParent = arguments[3];

			if (sourceNode && targetNode === undefined) {
				var newNode = sourceNode.cloneNode(true);
				tParent.nodeType !== 3 && tParent.nodeType !== 8 && tParent.appendChild(newNode);
			} else if (targetNode && sourceNode === undefined) {
				targetNode.parentElement.removeChild(targetNode);
			}
		}
	};
	Object.create(worker).replace(target, source);
};
///////////////////////////////////////

var state = {
	itemCounter: 0,
	toDoItems: [],
	filterSelect: 'all',
	allChecked: false
};

function encodeInput(v) {
	return v.replace(/[\"&<>\']/g, function (a) {
		return { '"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": "\'" }[a];
	});
}

function filterBy(filter) {
	state.toDoItems.forEach(function (i) {
		if (filter === 'all') {
			i.visible = true;
		} else if (filter === 'completed') {
			i.visible = i.checked;
		} else {
			i.visible = !i.checked;
		}
	});
	state.filterSelect = filter;
	buildApp(state);
}

function addToDo(self) {
	state.toDoItems.push({
		val: self.value,
		label: encodeInput(self.value),
		id: state.itemCounter++,
		checked: false,
		visible: state.filterSelect !== 'completed'
	});
	self.value = '';
	buildApp(state);
}

function checkToDo(id) {
	state.toDoItems.forEach(function (i) {
		if (i.id === id) {
			i.checked = !i.checked;
			i.visible = i.checked === true && state.filterSelect !== 'active' || i.checked === false && state.filterSelect !== 'completed';
		}
	});
	buildApp(state);
}

function removeToDo(id) {
	var newToDos = state.toDoItems.filter(function (i) {
		return i.id !== id;
	});
	state.toDoItems = newToDos;
	buildApp(state);
}

function toggleCheckAll() {
	state.allChecked = !state.allChecked;
	state.toDoItems.forEach(function (i) {
		i.checked = state.allChecked;
		i.visible = state.allChecked && state.filterSelect !== 'active' || state.allChecked === false && state.filterSelect !== 'completed';
	});
	buildApp(state);
}

function editToDo(val, id) {
	state.toDoItems.some(function (i) {
		if (i.id === id && val.innerText !== i.val) {
			i.val = val.innerText;
			i.label = encodeInput(val.innerText);
			buildApp(state);
			return true;
		}
		return false;
	});
}

function buildApp() {
	var newState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : state;

	var appString = '\n\t\t<section id="my-app">\n\t\t\t<div class="todo">\n\t\t\t\t<h1>todos</h1>\n\t\t\t\t<div class="posRel">\n\t\t\t\t\t<span onclick="toggleCheckAll()" class="' + (state.toDoItems.length ? 'toggleAll' : 'hidden') + '">\u276F</span>\n\t\t\t\t\t<input type="text" placeholder="What needs to be done?" onchange="addToDo(this)" />\n                </div>\n\t\t\t\t<div class="list-container">\n      \t\t\t  ' + newState.toDoItems.map(function (v) {
		return '\n\t\t\t\t\t<div class="' + (v.checked ? 'itemChecked' : '') + ' ' + (v.visible ? '' : 'hidden') + ' item">\n\t\t\t\t\t\t<div class="' + (v.checked ? 'isChecked' : '') + ' check" onClick="checkToDo(' + v.id + ')"></div>\n\t\t\t\t\t\t<svg onclick="removeToDo(' + v.id + ')" xmlns="http://www.w3.org/2000/svg" width="24" height="24">\n\t\t\t\t\t\t\t<path d="M3 6v18h18V6H3zm5 14a1 1 0 0 1-2 0V10a1 1 0 0 1 2 0v10zm5 0a1 1 0 0 1-2 0V10a1 1 0 0 1 2 0v10zm5 0a1 1 0 0 1-2 0V10a1 1 0 0 1 2 0v10zm4-18v2H2V2h5.711c.9 0 1.631-1.099 1.631-2h5.315c0 .901.73 2 1.631 2H22z"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t<span contenteditable onblur="editToDo(this, ' + v.id + ')">' + v.label + '</span>\n\t\t\t\t\t</div>\n\t\t\t\t  ';
	}).join('') + '\n\t\t\t\t\t' + (newState.toDoItems.length ? '\n\t\t\t\t\t<div class="filter">\n\t\t\t\t\t\t<p>' + newState.toDoItems.filter(function (i) {
		return !i.checked;
	}).length + ' Items left</p>\n\t\t\t\t\t\t<button onclick="filterBy(\'all\')" class="' + (state.filterSelect === 'all' ? 'selected' : '') + '">All</button>\n\t\t\t\t\t\t<button onclick="filterBy(\'active\')" class="' + (state.filterSelect === 'active' ? 'selected' : '') + '">Active</button>\n\t\t\t\t\t\t<button onclick="filterBy(\'completed\')" class="' + (state.filterSelect === 'completed' ? 'selected' : '') + '">Completed</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t' : '') + '\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</section>\n\t';
	vDiff(document.querySelector('#my-app'), appString);
}

buildApp();

Comments