wbotelhos/notify

View on GitHub
lib/jquery.notify.js

Summary

Maintainability
B
5 hrs
Test Coverage
/*!
 * jQuery Notify - A Notifier Plugin
 *
 * The MIT License
 *
 * author:  Washington Botelho
 * github:  wbotelhos/notify
 * version: 0.1.0
 *
 */

function Notify(options, params) {
  'use strict';

  if (typeof(options) === 'string') {
    params      = params || {};
    params.body = options;
    options     = params;
  }

  this.opt     = $.extend(true, {}, $.notify.defaults, options);
  this.wrapper = this._wrapper();
  this.hash    = this._hash();
}

Notify.prototype._afterOpen = function() {
  'use strict';

  this._execute('afterOpen');
};

Notify.prototype._bindClick = function() {
  'use strict';

  this.item.on('click.notify', this._onClick.bind(this));
};

Notify.prototype._bindMouseenter = function() {
  'use strict';

  this.item.on('mouseenter.notify', this._onMouseenter.bind(this));
};

Notify.prototype._bindMouseleave = function() {
  'use strict';

  this.item.on('mouseleave.notify', this._onMouseleave.bind(this));
};

Notify.prototype._body = function() {
  'use strict';

  return $('<p />', { html: this.opt.body });
};

Notify.prototype._build = function() {
  'use strict';

  var item = this._item();

  if (this.opt.icon) {
    item.addClass('notify-icon').append(this._icon());
  } else if (this.opt.image) {
    item.addClass('notify-image').append(this._image());
  }

  if (this.opt.title) {
    item.append(this._title());
  }

  return item.append(this._body());
};

Notify.prototype._checkWrapper = function() {
  'use strict';

  if (!this.wrapper.children().length) {
    this.wrapper.remove();
  }
};

Notify.prototype._close = function(evt) {
  'use strict';

  if (this._execute('beforeClose', [evt])) {
    this.item.remove();

    this._pipe();

    if (this.opt.destroy) {
      this._checkWrapper();
    }

    this._execute('afterClose');
  }
};

Notify.prototype._create = function() {
  'use strict';

  this.item = this._build();

  this._bindClick();
  this._bindMouseenter();

  if (!this.opt.forever) {
    this._scheduleClose();
    this._bindMouseleave();
  }

  this._position(this.opt.position);
  this._open();
};

Notify.prototype._execute = function(name, args) {
  'use strict';

  var execute;

  if ($.isFunction(this.opt[name])) {
    execute = this.opt[name].apply(this, args);
  }

  return execute || execute === undefined;
};

Notify.prototype._hash = function() {
  'use strict';

  return +new Date();
};

Notify.prototype._hide = function() {
  'use strict';

  this.item.animate({ opacity: 0 }, this.opt.hideTime, this._minimize.bind(this));
};

Notify.prototype._icon = function() {
  'use strict';

  return $('<i />', { 'class': this.opt.icon });
};

Notify.prototype._image = function() {
  'use strict';

  return $('<img />', { src: this.opt.image });
};

Notify.prototype._item = function() {
  'use strict';

  return $('<div />', { 'class': this.opt.id });
};

Notify.prototype._minimize = function() {
  'use strict';

  this.item.animate({ height: 0 }, this.opt.minimizeTime, this._close.bind(this));
};

Notify.prototype._onClick = function(evt) {
  'use strict';

  if (this._execute('click', [evt]) && this.opt.closeClick) {
    this._close();
  }
};

Notify.prototype._onMouseenter = function(evt) {
  'use strict';

  if (this._execute('mouseover', [evt])) {
    this._unscheduleClose();
  }
};

Notify.prototype._onMouseleave = function(evt) {
  'use strict';

  if (this._execute('mouseout', [evt])) {
    this._scheduleClose();
  }
};

Notify.prototype._open = function() {
  'use strict';

  if (this._execute('beforeOpen')) {
    this._show();
  }
};

Notify.prototype._pipe = function() {
  'use strict';

  $.notify.lives.shift();

  var piped = $.notify.queue.shift();

  if (piped) {
    $.notify.lives.push(piped);
    piped._create();
  }
};

Notify.prototype._push = function() {
  'use strict';

  var ok = $.notify.lives.length < this.opt.max;

  if (ok) {
    $.notify.lives.push(this);
  } else {
    $.notify.queue.push(this);
  }

  return ok;
};

Notify.prototype._scheduleClose = function() {
  'use strict';

  this[this._timeoutKey()] = setTimeout(this._hide.bind(this), this.opt.timeout);
};

Notify.prototype._show = function() {
  'use strict';

  var that = this;

  that.item
  .appendTo(that.wrapper)
  .fadeIn(that.opt.showTime, this._afterOpen.bind(this));
};

Notify.prototype._timeoutKey = function() {
  'use strict';

  return 'notify_' + this.hash;
};

Notify.prototype._title = function() {
  'use strict';

  return $('<strong />', { html: this.opt.title });
};

Notify.prototype._position = function(position) {
  'use strict';

  if (position) {
    this.wrapper[0].className = position;
  }
};

Notify.prototype._unscheduleClose = function() { // TODO: CHAge to unschedule
  'use strict';

  clearTimeout(this[this._timeoutKey()]);

  this.item.stop().css({ opacity: '', height: '' });
};

Notify.prototype._wrapper = function() {
  'use strict';

  var wrapper = $(this.opt.wrapper);

  if (!wrapper.length) {
    return $('<div />', { id: this.opt.wrapper.slice(1) }).appendTo('body');
  }

  return wrapper;
};

Notify.prototype.close = function() {
  'use strict';

  this._close();
};

Notify.prototype.position = function(position) {
  'use strict';

  this._position(position);
};

(function($) {
  'use strict';

  $.notify = function(options, params) {
    var notify = new Notify(options, params);

    if (notify._push()) {
      notify._create();
    }

    return notify;
  };

  $.notify.clean = function(name) {
    if (!name || name === 'queue') {
      $.notify.queue = [];
    }

    if (!name || name === 'lives') {
      $.notify.lives = [];
    }
  };

  $.notify.queue = [];
  $.notify.lives = [];

  $.notify.defaults = {
    afterClose:    undefined,
    afterOpen:     undefined,
    beforeClose:   undefined,
    beforeOpen:    undefined,
    body:          undefined,
    click:         undefined,
    closeClick:    true,
    destroy:       false,
    forever:       false,
    hideTime:      1000,
    icon:          undefined,
    id:            'notify-item',
    image:         undefined,
    max:           5,
    minimizeTime:  300,
    mouseout:      undefined,
    mouseover:     undefined,
    position:      undefined,
    showTime:      400,
    timeout:       5000,
    title:         undefined,
    wrapper:       '#notify'
  };
})(jQuery);