class ContextMenu
{
  constructor(x, y)
  {
    this.element = document.createElement("div");
    this.element.className = "contextmenu";
    this.element.style.left = x + "px";
    this.element.style.top = y + "px";
    this.element.tabIndex = 0;
    this.destroyed = false;
    
    this.submenu = undefined;
    
    this.element.addEventListener("blur", (e) =>
    {
      if(!this.isChildElement(e.relatedTarget))
        this.destroy();
    });
    
    this.rootMenu = this;
  }
  
  isChildElement(element)
  {
    while(element != null)
    {
      if(this.element == element)
        return true;
      
      element = element.parentElement;
    }
    return false;
  }
  
  appendToElement(parentElement)
  {
    parentElement.appendChild(this.element);
    this.element.focus();
  }
  
  addButton(label, clickDelegate, destroy)
  {
    if(destroy == null)
      destroy = true;

    let menuItem = document.createElement("div");
    menuItem.className = "menuitem";
    menuItem.innerText = label;
    
    menuItem.addEventListener("click", () => {
      if(clickDelegate)
        clickDelegate();
      
      if(destroy)
        this.rootMenu.destroy();
    });
    
    menuItem.addEventListener("mouseover", () => {
      if(this.submenu != undefined)
        this.submenu.destroy();
    });
    
    this.element.appendChild(menuItem);
    return menuItem;
  }

  addBreak()
  {
    let breakElement = document.createElement("hr");
    this.element.appendChild(breakElement);
    return breakElement;
  }
  
  addSubmenu(label)
  {
    let submenu = new ContextMenu(0, this.element.clientY);
    submenu.rootMenu = this;
    
    let button = this.addButton(label);
    button.style.cursor = "default";
    
    let rightArrow = document.createElement("span");
    rightArrow.style.float = "right";
    rightArrow.innerText = ">";
    button.appendChild(rightArrow);
    
    button.addEventListener("mouseover", () => {
      let x = this.element.offsetWidth;
      submenu.element.style.top = "0px";
      submenu.element.style.left = x + "px";
      submenu.destroyed = false;
      
      this.element.appendChild(submenu.element);
      this.submenu = submenu;
    });
    
    this.element.appendChild(button);
    
    return submenu;
  }
  
  destroy()
  {
    if(this.destroyed)
      return;
    
    this.destroyed = true;
    this.element.remove();
  }
}
@@ -828,25 +828,956 @@
 ;%0D%0A  %7D%0D%0A
-  %0D%0A  add
+%0D%0A  getButton(label)%0D%0A  %7B%0D%0A    for(let node of this.element.childNodes)%0D%0A      if(node.innerText == label)%0D%0A        return node;%0D%0A    return undefined;%0D%0A  %7D%0D%0A  %0D%0A  addButton(label, clickDelegate, destroy)%0D%0A  %7B%0D%0A    let menuItem = this.createButton(label, clickDelegate, destroy);%0D%0A    this.element.appendChild(menuItem);%0D%0A%0D%0A    return menuItem;%0D%0A  %7D%0D%0A  %0D%0A  addButtonBefore(nextLabel, label, clickDelegate, destroy)%0D%0A  %7B%0D%0A    let menuItem = this.createButton(label, clickDelegate, destroy);%0D%0A    let nextButton = this.getButton(nextLabel);%0D%0A%0D%0A    this.element.insertBefore(nextButton, menuItem);%0D%0A%0D%0A    return menuItem;%0D%0A  %7D%0D%0A  %0D%0A  addButtonAfter(previousLabel, label, clickDelegate, destroy)%0D%0A  %7B%0D%0A    let menuItem = this.createButton(label, clickDelegate, destroy);%0D%0A    let previousButton = this.getButton(previousLabel);%0D%0A    %0D%0A    this.element.insertBefore(previousButton.nextSibling, menuItem);%0D%0A%0D%0A    return menuItem;%0D%0A  %7D%0D%0A%0D%0A  create
 Button(l
@@ -2293,81 +2293,10 @@
 %0D%0A  
-  %7D);%0D%0A    %0D%0A    this.element.appendChild(menuItem);%0D%0A    return menuItem
+%7D)
 ;%0D%0A 

Create AddButtonBefore and AddButtonAfter functions for ContextMenu