# Code coverage report for slap/lib/ui/BaseElement.js

## Statements: 81.72% (76 / 93) Branches: 64.29% (27 / 42) Functions: 95% (19 / 20) Lines: 90.41% (66 / 73) Ignored: none

All files » slap/lib/ui/ » BaseElement.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    1051
    1
    1

    1

    1

    1
    31

    31

    31
    31
    31
    31
    31
    31
    31

    31

    1

    1
    2
    2
    2
    2
    2
    2

    1
    2
    2
    2
    2

    1
    2
    2
    2
    2

    2
    2

    1
    2

    1

    1
    7
    2

    1
    109

    1
    9
    9
    9

    1
    115

    1
    88
    88

    1

    1
    31
    31
    6
    6

    31
    31
    31
    31
    265

    1

    1
     var blessed = require('blessed');
    var _ = require('lazy.js');
    var Point = require('text-buffer/lib/point');

    var Slap = require('./Slap');

    var util = require('../util');

    function BaseElement (opts) {
      var self = this;

      Iif (!(self instanceof blessed.Node)) return new BaseElement(opts);

      opts = _(Slap.global.options.element).merge(opts || {}).toObject();
      Eif (!('slap' in opts)) opts.slap = Slap.global;
      if (!('parent' in opts)) opts.parent = opts.slap;
      if (self instanceof BaseElement) blessed.Box.call(self, opts); // this should not be called if an element inherits from built-in blessed classes
      if (self.parent instanceof Pane) self.pane = self.parent;
      self.slap = opts.slap;
      self.focusable = opts.focusable;

      process.nextTick(function () { self._initHandlers(); });
    }
    BaseElement.prototype.__proto__ = blessed.Box.prototype;

    BaseElement.prototype.walkDepthFirst = function (direction, after, fn) {
      Iif (arguments.length === 2) fn = after;
      var children = this.children.slice();
      Iif (direction === -1) children.reverse();
      Iif (after) children = children.slice(children.indexOf(after) + 1);
      return children.some(function (child) {
        return fn.apply(child, arguments) || BaseElement.prototype.walkDepthFirst.call(child, direction, fn);
      });
    };
    BaseElement.prototype.focusFirst = function (direction, after) {
      return this.walkDepthFirst(direction, after, function () {
        Eif (this.visible && this.focusable) {
          this.focus();
          return true;
        }
      });
    };
    BaseElement.prototype._focusDirection = function (direction) {
      var self = this;
      var descendantParent;
      var descendant = self.screen.focused;
      while (descendant.hasAncestor(self)) {
        descendantParent = descendant.parent;
        if (BaseElement.prototype.focusFirst.call(descendantParent, direction, descendant)) return self;
        descendant = descendantParent;
      }
      Iif (!self.focusFirst(direction)) throw new Error("no focusable descendant");
      return self;
    };
    BaseElement.prototype.focusNext = function () {
      return this._focusDirection(1);
    };
    BaseElement.prototype.focusPrev = function () {
      return this._focusDirection(-1);
    };
    BaseElement.prototype.focus = function () {
      if (!this.hasFocus()) return blessed.Box.prototype.focus.apply(this, arguments);
      return this;
    };
    BaseElement.prototype.isAttached = function () {
      return this.hasAncestor(this.screen);
    };
    BaseElement.prototype.hasFocus = function (asChild) {
      var self = this;
      var focused = self.screen.focused;
      return focused.visible && (focused === self || focused.hasAncestor(self) || (asChild && self.hasAncestor(focused)));
    };

    BaseElement.prototype.pos = function () {
      return new Point(this.top + this.itop, this.left + this.ileft);
    };
    BaseElement.prototype.size = function () {
      Iif (!this.isAttached()) return new Point(0, 0); // hack
      return new Point(this.height - this.iheight, this.width - this.iwidth);
    };

    BaseElement.prototype.shrinkWidth = function () { return this.content.length + this.iwidth; };

    BaseElement.prototype._initHandlers = function () {
      var self = this;
      self.on('focus', function () {
        logger.debug('focus', util.typeOf(self));
        if (!self.focusable) self.focusNext();
      });
      self.on('blur', function () { logger.debug('blur', util.typeOf(self)); });
      self.on('show', function () { self.setFront(); });
      self.on('keypress', _.noop); // 'element keypress' doesn't work correctly without this
      self.on('element keypress', function (el, ch, key) {
        switch (util.getBinding(self.options.bindings, key)) {
          case 'hide': self.hide(); return false;
          case 'focusNext': self.focusNext(); return false;
          case 'focusPrev': self.focusPrev(); return false;
        }
      });
    };

    module.exports = BaseElement;

    var Pane = require('./Pane'); // circular import