137 lines
3.6 KiB
JavaScript
137 lines
3.6 KiB
JavaScript
var $ = require('jquery');
|
|
var _ = require('underscore');
|
|
var Backbone = require('backbone');
|
|
var CoreView = require('backbone/core-view');
|
|
|
|
var DEFAULTS = {
|
|
width: 160,
|
|
speedIn: 150,
|
|
speedOut: 300,
|
|
verticalPosition: 'down',
|
|
horizontalPosition: 'right',
|
|
tick: 'right',
|
|
verticalOffset: 0,
|
|
horizontalOffset: 0
|
|
};
|
|
|
|
module.exports = CoreView.extend({
|
|
className: 'dropdown',
|
|
|
|
initialize: function (options) {
|
|
_.bindAll(this, 'open', 'hide', '_handleClick', '_keydown', '_onDocumentClick');
|
|
|
|
this.options = {};
|
|
// Extend options
|
|
_.defaults(this.options, options, DEFAULTS);
|
|
|
|
if (options.template) {
|
|
this.template = options.template;
|
|
}
|
|
|
|
// Bind to target
|
|
$(options.target).on('click', this._handleClick);
|
|
$(document).on('keydown', this._keydown);
|
|
$(document).on('click', this._onDocumentClick);
|
|
|
|
this.modelView = new Backbone.Model({
|
|
open: false
|
|
});
|
|
|
|
this.modelView.on('change:open', function (model, isOpen) {
|
|
isOpen ? this.hide() : this.open();
|
|
}, this);
|
|
},
|
|
|
|
render: function () {
|
|
// Render
|
|
var $el = this.$el;
|
|
$el
|
|
.html(this.template && this.template(this.options))
|
|
.css({
|
|
width: this.options.width
|
|
});
|
|
return this;
|
|
},
|
|
|
|
_handleClick: function (event) {
|
|
if (event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
var isOpen = this.modelView.get('open');
|
|
this.modelView.set('open', !isOpen);
|
|
},
|
|
|
|
_onDocumentClick: function (e) {
|
|
var $el = $(e.target);
|
|
var $target = $(this.options.target);
|
|
var isTarget = $el.get(0) === $target.get(0);
|
|
if (!isTarget && $el.closest('.Dropdown').length === 0) {
|
|
this.modelView.set({open: false}, {silent: true});
|
|
this.hide();
|
|
}
|
|
},
|
|
|
|
_keydown: function (event) {
|
|
if (event.keyCode === 27) {
|
|
this.modelView.set('open', false);
|
|
}
|
|
},
|
|
|
|
hide: function () {
|
|
this.$el.hide();
|
|
},
|
|
|
|
show: function () {
|
|
this.$el.css({
|
|
display: 'block',
|
|
opacity: 1
|
|
});
|
|
},
|
|
|
|
open: function (event, target) {
|
|
// Target
|
|
var $target = target && $(target) || this.options.target;
|
|
this.options.target = $target;
|
|
|
|
// Positionate
|
|
var targetPos = $target[this.options.position || 'offset']();
|
|
var targetWidth = $target.outerWidth();
|
|
var targetHeight = $target.outerHeight();
|
|
var elementWidth = this.$el.outerWidth();
|
|
var elementHeight = this.$el.outerHeight();
|
|
var verticalPosition = this.options.verticalPosition;
|
|
var verticalOffset = this.options.verticalOffset;
|
|
var horizontalPosition = this.options.horizontalPosition;
|
|
var horizontalOffset = this.options.horizontalOffset;
|
|
|
|
this.$el.css({
|
|
top: targetPos.top + parseInt((verticalPosition === 'up') ? (-elementHeight - 10 - verticalOffset) : (targetHeight + 10 - verticalOffset)),
|
|
left: targetPos.left + parseInt((horizontalPosition === 'left') ? (horizontalOffset - 15) : (targetWidth - elementWidth + 15 - horizontalOffset))
|
|
})
|
|
.addClass(
|
|
// Add vertical and horizontal position class
|
|
(verticalPosition === 'up' ? 'vertical_top' : 'vertical_bottom') +
|
|
' ' +
|
|
(horizontalPosition === 'right' ? 'horizontal_right' : 'horizontal_left') +
|
|
' ' +
|
|
// Add tick class
|
|
'tick_' + this.options.tick
|
|
);
|
|
|
|
this.show();
|
|
},
|
|
|
|
isOpen: function () {
|
|
return this.modelView.get('open');
|
|
},
|
|
|
|
clean: function () {
|
|
const target = $(this.options.target);
|
|
this.options.target && target.off('click', this._handleClick);
|
|
$(document).off('keydown', this._keydown);
|
|
$(document).off('click', this._onDocumentClick);
|
|
CoreView.prototype.clean.apply(this);
|
|
}
|
|
});
|