<section id="buttons">
  <input id="addRootInput" type="text"/><button id="addRootButton">Add root</button>
  <input id="findParentInput" type="text"/><button id="findParentButton">Find parent</button>
  <input id="addChildInput" type="text"/><button id="addChildButton">Add child</button>
  <input id="removeChildInput" type="text"/><button id="removeChildButton">Remove child</button>
</section>

<section id="display">
  <div id="treeResult">
    <ul id="root">
    </ul>
  </div>
  <div id="searchResult"></div>
</section>
* {
  box-sizing: border-box;
  font-family: Arial;
}

*:focus {
  outline: none;
}

#buttons {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: 
    "addRootInput addRootButton"
    "findParentInput findParentButton"
    "addChildInput addChildButton"
    "removeChildInput removeChildButton";
}

#addRootInput {
  grid-area: addRootInput;
}

#addRootButton {
  grid-area: addRootButton;
}

#findParentInput {
  grid-area: findParentInput;
}

#findParentButton {
  grid-area: findParentButton;
}

#addChildInput {
  grid-area: addChildInput;
}

#addChildButton {
  grid-area: addChildButton;
}

#removeChildInput {
  grid-area: removeChildInput;
}

#removeChildButton {
  grid-area: removeChildButton;
}

input {
  width: 200px;
  font-size: 16px;
  margin: 5px 0;
  padding: 10px;
  justify-self: end;
  border: 1px solid black;
  border-radius: 40px;
  transition: all 0.2s ease;
}

input:focus, input:hover {
  border: 1px solid blue;
  box-shadow: 0 0 5px black;
}

button {
  width: 200px;
  font-size: 16px;
  margin: 5px 0;
  padding: 5px;
  justify-self: start;
  background-color: white;
  border: 1px solid black;
  border-radius: 40px;
  cursor: pointer;
  transition: all 0.2s ease;
}

button:focus, button:hover {
  background-color: black;
  color: white;
  box-shadow: 0 0 5px black;
}



#display {
  margin: 25px 0 0;
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-areas: "treeResult searchResult";
}

#searchResult {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 200px;
}
// Tree
const Tree = function(content) {
  this.content = content;
  this.children = [];
};


// findObject
Tree.prototype.findObject = function(target) {  
  if (!(target instanceof Tree)) {
    target = new Tree(target);
  }
  
  const recurse = (obj) => {
    if (obj === target) {
      return obj;
    }
    
    for (let i = 0; i < obj.children.length; i++) {
      return recurse(obj.children[i]);
    }
  };
  
  return recurse(this) || null;
};


// findFirstValue (BFS)
Tree.prototype.findFirstValue = function(target) {
  if (!target) {
    return;
  }
  
  const queue = [this];
  let i = 0;
  
  while (i < queue.length) {
    const dequeued = queue[i];
    if (dequeued.content === target) {
      return dequeued;
    }
    queue.push(...dequeued.children);
    i++;
  }
  
  return null;
};


// findAllValues (BFS)
Tree.prototype.findAllValues = function(target) {
  if (!target) {
    return;
  }
  
  const queue = [this];
  const result = [];
  let i = 0;
  
  while (i < queue.length) {
    const dequeued = queue[i];
    if (dequeued.content === target) {
      result.push(dequeued);
    }
    queue.push(...dequeued.children);
    i++;
  }
  
  return result.length > 0 ? result : null;
};


// addChild
Tree.prototype.addChild = function(obj) {
  if (!(obj instanceof Tree)) {
    obj = new Tree(obj);
  }
  
  this.children.push(obj);
  return obj;
};


// removeChild
Tree.prototype.removeChild = function(target) {
  let index;
  if (target instanceof Tree) {
    index = this.children.indexOf(target);
  } else {
    index = this.children.findIndex(child => child.content === target);
  }

  if (index > -1) {
    return this.children.splice(index, 1)[0];
  } else {
    return null;
  }
};


// GLOBALS
let tree;
let foundNode;

// focus on first input on load
document.querySelector('#addRootInput').focus();

// add button click event listeners
document.querySelector('#buttons').addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const text = e.target.innerText;
    if (text === 'Add root') {
      addRoot(e);
    } else if (text === 'Find parent') {
      findParent(e);
    } else if (text === 'Add child') {
      addChild(e);
    } else if (text === 'Remove child') {
      removeChild(e);
    }
    
    e.target.blur();
  }
});


// addRoot
function addRoot(e) {
  const input = e.target.previousElementSibling;
  
  if (input.value === '') {
    input.focus();
    return;
  }
  
  // reset DOM
  const root = document.getElementById('root');
  root.innerHTML = '';
  const searchResult = document.getElementById('searchResult');
  searchResult.innerHTML = '';
  searchResult.removeAttribute('style');
  
  // make tree
  tree = new Tree(input.value);
  
  // add root to DOM
  const li = document.createElement('li');
  li.innerText = input.value;
  root.append(li);
  
  // reset user input
  input.value = '';
  input.focus();
}


// findParent
function findParent(e) {
  const input = e.target.previousElementSibling;
  if (!tree) {
    input.select();
    return;
  };
  
  foundNode = tree.findFirstValue(input.value);
  const searchResult = document.getElementById('searchResult');
  searchResult.innerHTML = '';
  
  if (foundNode) {
    const h1 = document.createElement('h1');
    h1.innerText = 'Current Parent';
    const para = document.createElement('p');
    para.innerText = foundNode.content;

    searchResult.append(h1, para);
    searchResult.style.border = '1px solid black';
    
  } else {
    const h1 = document.createElement('h1');
    h1.innerText = 'No Parent Found';
    
    searchResult.append(h1);
    searchResult.style.border = '1px solid black';
  }
  
  input.value = '';
  input.focus();
}


// addChild to foundNode
function addChild(e) {
  const input = e.target.previousElementSibling;
  if (input.value === '') {
    input.focus();
    return;
  }
  
  if (!foundNode) {
    input.value = '';
    document.querySelector('#findParentInput').focus();
    return;
  }
  
  foundNode.addChild(input.value);
  
  // find all list items
  const listItems = document.getElementsByTagName('LI');
  
  // find parent
  let parent;
  for (let i = 0; i < listItems.length; i++) {
    const content = listItems[i].innerText.split('\n')[0];
    if (content === foundNode.content) {
      parent = listItems[i];
    }
  }
  
  if (!parent) return;
  
  // add to DOM
  const li = document.createElement('li');
  li.innerText = input.value;
  const ul = document.createElement('ul');
  ul.append(li);
  parent.append(ul);
  
  input.value = '';
  input.focus();
}


// removeChild from foundNode
function removeChild(e) {
  const input = e.target.previousElementSibling;
  
  if ((input.value === '' && !foundNode) || (!foundNode)) {
    input.value = '';
    document.querySelector('#findParentInput').focus();
    return;
  } else if (input.value === '') {
    input.focus();
    return;
  }

  
  const removedChild = foundNode.removeChild(input.value);
  if (!removedChild) {
    input.select();
    return
  };
  
  // find all list items
  const listItems = document.getElementsByTagName('LI');
  
  // find li and remove
  let li;
  for (let i = 0; i < listItems.length; i++) {
    const content = listItems[i].innerText.split('\n')[0];
    if (content === input.value) {
      listItems[i].parentElement.remove();
      break;
    }
  }
  
  input.value = '';
  input.focus();
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.