keeweb/app/scripts/views/menu/menu-item-view.js

261 lines
8.0 KiB
JavaScript

const Backbone = require('backbone');
const KeyHandler = require('../../comp/key-handler');
const Keys = require('../../const/keys');
const Alerts = require('../../comp/alerts');
const DragDropInfo = require('../../comp/drag-drop-info');
const Locale = require('../../util/locale');
const MenuItemView = Backbone.View.extend({
template: require('templates/menu/menu-item.hbs'),
events: {
'mouseover': 'mouseover',
'mouseout': 'mouseout',
'click .menu__item-option': 'selectOption',
'click': 'selectItem',
'dblclick': 'expandItem',
'click .menu__item-edit': 'editItem',
'click .menu__item-empty-trash': 'emptyTrash',
'dragstart': 'dragstart',
'dragover': 'dragover',
'dragleave': 'dragleave',
'drop': 'drop',
'dragover .menu__item-drag-top': 'dragoverTop',
'dragleave .menu__item-drag-top': 'dragleaveTop'
},
iconEl: null,
itemViews: null,
initialize: function() {
this.itemViews = [];
this.listenTo(this.model, 'change:title', this.changeTitle);
this.listenTo(this.model, 'change:icon', this.changeIcon);
this.listenTo(this.model, 'change:customIconId', this.render);
this.listenTo(this.model, 'change:active', this.changeActive);
this.listenTo(this.model, 'change:expanded', this.changeExpanded);
this.listenTo(this.model, 'change:cls', this.changeCls);
this.listenTo(this.model, 'delete', this.remove);
this.listenTo(this.model, 'insert', this.insertItem);
const shortcut = this.model.get('shortcut');
if (shortcut) {
KeyHandler.onKey(shortcut, this.selectItem, this, KeyHandler.SHORTCUT_OPT);
if (shortcut !== Keys.DOM_VK_C) {
KeyHandler.onKey(shortcut, this.selectItem, this, KeyHandler.SHORTCUT_ACTION);
}
}
},
render: function() {
this.removeInnerViews();
this.renderTemplate(this.model.attributes);
this.iconEl = this.$el.find('i.menu__item-icon');
const items = this.model.get('items');
if (items) {
items.forEach(function(item) {
if (item.get('visible')) {
this.insertItem(item);
}
}, this);
}
this.$el.toggleClass('menu__item--collapsed', !this.model.get('expanded'));
return this;
},
insertItem: function(item) {
this.itemViews.push(new MenuItemView({ el: this.$el, model: item }).render());
},
remove: function() {
this.removeInnerViews();
const shortcut = this.model.get('shortcut');
if (shortcut) {
KeyHandler.offKey(shortcut, this.selectItem, this, KeyHandler.SHORTCUT_OPT);
if (shortcut !== Keys.DOM_VK_C) {
KeyHandler.offKey(shortcut, this.selectItem, this, KeyHandler.SHORTCUT_ACTION);
}
}
Backbone.View.prototype.remove.apply(this, arguments);
},
removeInnerViews: function() {
this.itemViews.forEach(itemView => itemView.remove());
this.itemViews = [];
},
changeTitle: function(model, title) {
this.$el
.find('.menu__item-title')
.first()
.text(title || '(no title)');
},
changeIcon: function(model, icon) {
this.iconEl[0].className = 'menu__item-icon fa ' + (icon ? 'fa-' + icon : 'menu__item-icon--no-icon');
},
changeActive: function(model, active) {
this.$el.toggleClass('menu__item--active', active);
},
changeExpanded: function(model, expanded) {
this.$el.toggleClass('menu__item--collapsed', !expanded);
this.model.setExpanded(expanded);
},
changeCls: function(model, cls) {
const oldCls = model.previousAttributes().cls;
if (oldCls) {
this.$el.removeClass(oldCls);
}
this.$el.addClass(cls);
},
mouseover: function(e) {
if (!e.button) {
this.$el.addClass('menu__item--hover');
e.stopPropagation();
}
},
mouseout: function(e) {
this.$el.removeClass('menu__item--hover');
e.stopPropagation();
},
selectItem: function(e) {
e.stopPropagation();
e.preventDefault();
if (this.model.get('active')) {
return;
}
if (this.model.get('disabled')) {
Alerts.info(this.model.get('disabled'));
} else {
Backbone.trigger('menu-select', { item: this.model });
}
},
selectOption: function(e) {
const options = this.model.get('options');
const value = $(e.target).data('value');
if (options && options.length) {
const option = options.find(op => op.get('value') === value);
if (option) {
Backbone.trigger('menu-select', { item: this.model, option: option });
}
}
e.stopImmediatePropagation();
e.preventDefault();
},
expandItem: function(e) {
if (this.model.toggleExpanded) {
this.model.toggleExpanded();
}
e.stopPropagation();
},
editItem: function(e) {
if (this.model.get('active') && this.model.get('editable')) {
e.stopPropagation();
switch (this.model.get('filterKey')) {
case 'tag':
Backbone.trigger('edit-tag', this.model);
break;
case 'group':
Backbone.trigger('edit-group', this.model);
break;
}
}
},
emptyTrash: function(e) {
e.stopPropagation();
Alerts.yesno({
header: Locale.menuEmptyTrashAlert,
body: Locale.menuEmptyTrashAlertBody,
icon: 'minus-circle',
success: function() {
Backbone.trigger('empty-trash');
}
});
},
dropAllowed(e) {
const types = e.originalEvent.dataTransfer.types;
for (let i = 0; i < types.length; i++) {
if (types[i] === 'text/group' || types[i] === 'text/entry') {
return true;
}
}
return false;
},
dragstart(e) {
e.stopPropagation();
if (this.model.get('drag')) {
e.originalEvent.dataTransfer.setData('text/group', this.model.id);
e.originalEvent.dataTransfer.effectAllowed = 'move';
DragDropInfo.dragObject = this.model;
}
},
dragover(e) {
if (this.model.get('drop') && this.dropAllowed(e)) {
e.stopPropagation();
e.preventDefault();
this.$el.addClass('menu__item--drag');
}
},
dragleave(e) {
e.stopPropagation();
if (this.model.get('drop') && this.dropAllowed(e)) {
this.$el.removeClass('menu__item--drag menu__item--drag-top');
}
},
drop(e) {
e.stopPropagation();
if (this.model.get('drop') && this.dropAllowed(e)) {
const isTop = this.$el.hasClass('menu__item--drag-top');
this.$el.removeClass('menu__item--drag menu__item--drag-top');
if (isTop) {
this.model.moveToTop(DragDropInfo.dragObject);
} else {
if (this.model.get('filterKey') === 'trash') {
DragDropInfo.dragObject.moveToTrash();
} else {
this.model.moveHere(DragDropInfo.dragObject);
}
}
Backbone.trigger('refresh');
}
},
dropTopAllowed(e) {
const types = e.originalEvent.dataTransfer.types;
for (let i = 0; i < types.length; i++) {
if (types[i] === 'text/group') {
return true;
}
}
return false;
},
dragoverTop(e) {
if (this.dropTopAllowed(e)) {
this.$el.addClass('menu__item--drag-top');
}
},
dragleaveTop(e) {
if (this.dropTopAllowed(e)) {
this.$el.removeClass('menu__item--drag-top');
}
}
});
module.exports = MenuItemView;