function CPHContextMenu (app, cfg) {

  this.app = app;

  this.items = cfg.items || [];
  this.parent = cfg.parent || this;
  this.data = cfg.data || null;

  this.constructor.activeMenu &&
    this.constructor.activeMenu.close();
  this.constructor.activeMenu = this;

  this.items = this.items.map(function (item) {
    if (item.shortcut && !item.action && this.parent && this.parent.shortcut) {
      item.action = function (data, e) {
        this.parent.focus();
        this.parent.shortcut(item.shortcut);
      }.bind(this);
    }
    return item;
  }.bind(this));

  Control.call(this);

  var itemEls = this.selectorAll('[data-item-index]');

  itemEls.forEach(function (el, i) {
    var index = parseInt(el.getAttribute('data-item-index'));
    var item = this.items[index];
    if (!item) {
      return;
    }
    var hidden = item.hidden;
    hidden = typeof hidden === 'function'
      ? !!hidden.call(this.parent, this.data)
      : !!hidden;
    if (hidden) {
      el.style.display = 'none';
    }
    var disabled = item.disabled || !!item.disabledAsync;
    if (typeof disabled === 'function') {
      disabled = disabled.call(this.parent, this.data);
    } else if (typeof item.disabledAsync === 'function') {
      item.disabledAsync.call(this.parent, this.data, function (result) {
        disabled = !!result;
        !disabled && item.classList.remove('disabled');
      });
    }
    disabled && el.classList.add('disabled');
    el.addEventListener('click', function (e) {
      if (disabled) {
        e.preventDefault();
        return;
      } else if (item.action) {
        e.preventDefault();
        this.close.call(this, item.action.bind(this.parent, this.data, e));
      } else if (item.href) {
        setTimeout(function () {
          this.close();
        }.bind(this), 1);
      }
    }.bind(this), true);
  }.bind(this));

}
Retrieve annotations for a specific line number
@param {array} annotations an array of {image: '', text: '', url: ''}