/* * (c) Copyright Ascensio System SIA 2010-2015 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, * EU, LV-1021. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ if (Common === undefined) { var Common = {}; } define(["common/main/lib/component/BaseView", "common/main/lib/component/Scroller"], function () { Common.UI.DataViewGroupModel = Backbone.Model.extend({ defaults: function () { return { id: Common.UI.getId(), caption: "" }; } }); Common.UI.DataViewGroupStore = Backbone.Collection.extend({ model: Common.UI.DataViewGroupModel }); Common.UI.DataViewModel = Backbone.Model.extend({ defaults: function () { return { id: Common.UI.getId(), selected: false, allowSelected: true, value: null }; } }); Common.UI.DataViewStore = Backbone.Collection.extend({ model: Common.UI.DataViewModel }); Common.UI.DataViewItem = Common.UI.BaseView.extend({ options: {}, template: _.template(['
<%= value %>
'].join("")), initialize: function (options) { Common.UI.BaseView.prototype.initialize.call(this, options); var me = this; me.template = me.options.template || me.template; me.listenTo(me.model, "change", me.render); me.listenTo(me.model, "change:selected", me.onSelectChange); me.listenTo(me.model, "remove", me.remove); }, render: function () { if (_.isUndefined(this.model.id)) { return this; } var el = $(this.el); el.html(this.template(this.model.toJSON())); el.toggleClass("selected", this.model.get("selected") && this.model.get("allowSelected")); el.off("click").on("click", _.bind(this.onClick, this)); el.off("dblclick").on("dblclick", _.bind(this.onDblClick, this)); if (!_.isUndefined(this.model.get("cls"))) { el.addClass(this.model.get("cls")); } this.trigger("change", this, this.model); return this; }, remove: function () { this.stopListening(this.model); this.trigger("remove", this, this.model); Common.UI.BaseView.prototype.remove.call(this); }, onClick: function (e) { this.trigger("click", this, this.model, e); }, onDblClick: function (e) { this.trigger("dblclick", this, this.model, e); }, onSelectChange: function (model, selected) { this.trigger("select", this, model, selected); } }); Common.UI.DataView = Common.UI.BaseView.extend({ options: { multiSelect: false, handleSelect: true, enableKeyEvents: true, keyMoveDirection: "both", restoreHeight: 0, emptyText: "", listenStoreEvents: true, allowScrollbar: true }, template: _.template(['
', "<% _.each(groups, function(group) { %>", '
', '
', "<%= group.caption %>", "
", '
', "
", "
", "<% }); %>", "
"].join("")), initialize: function (options) { Common.UI.BaseView.prototype.initialize.call(this, options); var me = this; me.template = me.options.template || me.template; me.store = me.options.store || new Common.UI.DataViewStore(); me.groups = me.options.groups || null; me.itemTemplate = me.options.itemTemplate || null; me.multiSelect = me.options.multiSelect; me.handleSelect = me.options.handleSelect; me.parentMenu = me.options.parentMenu; me.enableKeyEvents = me.options.enableKeyEvents; me.style = me.options.style || ""; me.emptyText = me.options.emptyText || ""; me.listenStoreEvents = (me.options.listenStoreEvents !== undefined) ? me.options.listenStoreEvents : true; me.allowScrollbar = (me.options.allowScrollbar !== undefined) ? me.options.allowScrollbar : true; me.rendered = false; me.dataViewItems = []; if (me.options.keyMoveDirection == "vertical") { me.moveKeys = [Common.UI.Keys.UP, Common.UI.Keys.DOWN]; } else { if (me.options.keyMoveDirection == "horizontal") { me.moveKeys = [Common.UI.Keys.LEFT, Common.UI.Keys.RIGHT]; } else { me.moveKeys = [Common.UI.Keys.UP, Common.UI.Keys.DOWN, Common.UI.Keys.LEFT, Common.UI.Keys.RIGHT]; } } if (me.options.el) { me.render(); } }, render: function (parentEl) { var me = this; this.trigger("render:before", this); this.cmpEl = $(this.el); if (parentEl) { this.setElement(parentEl, false); this.cmpEl = $(this.template({ groups: me.groups ? me.groups.toJSON() : null, style: me.style })); parentEl.html(this.cmpEl); } else { this.cmpEl.html(this.template({ groups: me.groups ? me.groups.toJSON() : null, style: me.style })); } if (!this.rendered) { if (this.listenStoreEvents) { this.listenTo(this.store, "add", this.onAddItem); this.listenTo(this.store, "reset", this.onResetItems); } this.onResetItems(); if (this.parentMenu) { this.cmpEl.closest("li").css("height", "100%"); this.cmpEl.css("height", "100%"); this.parentMenu.on("show:after", _.bind(this.alignPosition, this)); } if (this.enableKeyEvents && this.parentMenu && this.handleSelect) { this.parentMenu.on("show:after", function () { me.showLastSelected(); Common.NotificationCenter.trigger("dataview:focus"); }); this.parentMenu.on("hide:after", function () { Common.NotificationCenter.trigger("dataview:blur"); }); } } if (_.isUndefined(this.scroller) && this.allowScrollbar) { this.scroller = new Common.UI.Scroller({ el: $(this.el).find(".inner").andSelf().filter(".inner"), useKeyboard: this.enableKeyEvents && !this.handleSelect, minScrollbarLength: 40 }); } var modalParents = this.cmpEl.closest(".asc-window"); if (modalParents.length > 0) { this.tipZIndex = parseInt(modalParents.css("z-index")) + 10; } this.rendered = true; this.cmpEl.on("click", function (e) { if (/dataview/.test(e.target.className)) { return false; } }); this.trigger("render:after", this); return this; }, setStore: function (store) { if (store) { this.stopListening(this.store); this.store = store; if (this.listenStoreEvents) { this.listenTo(this.store, "add", this.onAddItem); this.listenTo(this.store, "reset", this.onResetItems); } } }, selectRecord: function (record, suspendEvents) { if (!this.handleSelect) { return; } if (suspendEvents) { this.suspendEvents(); } if (!this.multiSelect) { _.each(this.store.where({ selected: true }), function (rec) { rec.set({ selected: false }); }); if (record) { record.set({ selected: true }); } } else { if (record) { record.set({ selected: !record.get("selected") }); } } if (suspendEvents) { this.resumeEvents(); } }, selectByIndex: function (index, suspendEvents) { if (this.store.length > 0 && index > -1 && index < this.store.length) { this.selectRecord(this.store.at(index), suspendEvents); } }, deselectAll: function (suspendEvents) { if (suspendEvents) { this.suspendEvents(); } _.each(this.store.where({ selected: true }), function (record) { record.set({ selected: false }); }); if (suspendEvents) { this.resumeEvents(); } }, getSelectedRec: function () { if (this.multiSelect) { var items = []; _.each(this.store.where({ selected: true }), function (rec) { items.push(rec); }); return items; } return this.store.where({ selected: true }); }, onAddItem: function (record, index, opts) { var view = new Common.UI.DataViewItem({ template: this.itemTemplate, model: record }); if (view) { var innerEl = $(this.el).find(".inner").andSelf().filter(".inner"); if (this.groups && this.groups.length > 0) { var group = this.groups.findWhere({ id: record.get("group") }); if (group) { innerEl = innerEl.find("#" + group.id + " " + ".group-items-container"); } } if (innerEl) { if (opts && opts.at == 0) { innerEl.prepend(view.render().el); } else { innerEl.append(view.render().el); } innerEl.find(".empty-text").remove(); this.dataViewItems.push(view); if (record.get("tip")) { var view_el = $(view.el); view_el.attr("data-toggle", "tooltip"); view_el.tooltip({ title: record.get("tip"), placement: "cursor", zIndex: this.tipZIndex }); } this.listenTo(view, "change", this.onChangeItem); this.listenTo(view, "remove", this.onRemoveItem); this.listenTo(view, "click", this.onClickItem); this.listenTo(view, "dblclick", this.onDblClickItem); this.listenTo(view, "select", this.onSelectItem); if (!this.isSuspendEvents) { this.trigger("item:add", this, view, record); } } } }, onResetItems: function () { $(this.el).html(this.template({ groups: this.groups ? this.groups.toJSON() : null, style: this.style })); if (!_.isUndefined(this.scroller)) { this.scroller.destroy(); delete this.scroller; } if (this.store.length < 1 && this.emptyText.length > 0) { $(this.el).find(".inner").andSelf().filter(".inner").append('
' + this.emptyText + "
"); } _.each(this.dataViewItems, function (item) { this.stopListening(item); item.stopListening(item.model); }, this); this.dataViewItems = []; this.store.each(this.onAddItem, this); if (this.allowScrollbar) { this.scroller = new Common.UI.Scroller({ el: $(this.el).find(".inner").andSelf().filter(".inner"), useKeyboard: this.enableKeyEvents && !this.handleSelect, minScrollbarLength: 40 }); } this.attachKeyEvents(); }, onChangeItem: function (view, record) { if (!this.isSuspendEvents) { this.trigger("item:change", this, view, record); } }, onRemoveItem: function (view, record) { this.stopListening(view); view.stopListening(); if (this.store.length < 1 && this.emptyText.length > 0) { var el = $(this.el).find(".inner").andSelf().filter(".inner"); if (el.find(".empty-text").length <= 0) { el.append('
' + this.emptyText + "
"); } } for (var i = 0; i < this.dataViewItems.length; i++) { if (_.isEqual(view, this.dataViewItems[i])) { this.dataViewItems.splice(i, 1); break; } } if (!this.isSuspendEvents) { this.trigger("item:remove", this, view, record); } }, onClickItem: function (view, record, e) { if (this.disabled) { return; } window._event = e; this.selectRecord(record); this.lastSelectedRec = undefined; var tip = view.$el.data("bs.tooltip"); if (tip) { tip.hide(); } if (!this.isSuspendEvents) { this.trigger("item:click", this, view, record, e); } }, onDblClickItem: function (view, record, e) { if (this.disabled) { return; } window._event = e; this.selectRecord(record); this.lastSelectedRec = undefined; if (!this.isSuspendEvents) { this.trigger("item:dblclick", this, view, record, e); } }, onSelectItem: function (view, record, selected) { if (!this.isSuspendEvents) { this.trigger(selected ? "item:select": "item:deselect", this, view, record); } }, scrollToRecord: function (record) { var innerEl = $(this.el).find(".inner"); var inner_top = innerEl.offset().top; var div = innerEl.find("#" + record.get("id")); var div_top = div.offset().top; if (div_top < inner_top || div_top + div.height() > inner_top + innerEl.height()) { if (this.scroller && this.allowScrollbar) { this.scroller.scrollTop(innerEl.scrollTop() + div_top - inner_top, 0); } else { innerEl.scrollTop(innerEl.scrollTop() + div_top - inner_top); } } }, onKeyDown: function (e, data) { if (this.disabled) { return; } if (data === undefined) { data = e; } if (_.indexOf(this.moveKeys, data.keyCode) > -1 || data.keyCode == Common.UI.Keys.RETURN) { data.preventDefault(); data.stopPropagation(); var rec = this.getSelectedRec()[0]; if (this.lastSelectedRec === undefined) { this.lastSelectedRec = rec; } if (data.keyCode == Common.UI.Keys.RETURN) { this.lastSelectedRec = undefined; this.trigger("item:click", this, this, rec, e); this.trigger("item:select", this, this, rec, e); this.trigger("entervalue", this, rec, e); } else { var idx = _.indexOf(this.store.models, rec); idx = (data.keyCode == Common.UI.Keys.UP || data.keyCode == Common.UI.Keys.LEFT) ? Math.max(0, idx - 1) : Math.min(this.store.length - 1, idx + 1); rec = this.store.at(idx); if (rec) { this.selectRecord(rec); this.scrollToRecord(rec); } } } }, attachKeyEvents: function () { if (this.enableKeyEvents && this.handleSelect) { var el = $(this.el).find(".inner").andSelf().filter(".inner"); el.addClass("canfocused"); el.attr("tabindex", "0"); el.on((this.parentMenu) ? "dataview:keydown": "keydown", _.bind(this.onKeyDown, this)); } }, showLastSelected: function () { if (this.lastSelectedRec) { this.selectRecord(this.lastSelectedRec, true); this.scrollToRecord(this.lastSelectedRec); this.lastSelectedRec = undefined; } }, setDisabled: function (disabled) { this.disabled = disabled; $(this.el).find(".inner").andSelf().filter(".inner").toggleClass("disabled", disabled); }, isDisabled: function () { return this.disabled; }, alignPosition: function () { var menuRoot = (this.parentMenu.cmpEl.attr("role") === "menu") ? this.parentMenu.cmpEl : this.parentMenu.cmpEl.find("[role=menu]"), innerEl = $(this.el).find(".inner").andSelf().filter(".inner"), docH = $(document).height(), menuH = menuRoot.outerHeight(), top = parseInt(menuRoot.css("top")); if (menuH > docH) { innerEl.css("max-height", (docH - parseInt(menuRoot.css("padding-top")) - parseInt(menuRoot.css("padding-bottom")) - 5) + "px"); if (this.allowScrollbar) { this.scroller.update({ minScrollbarLength: 40 }); } } else { if (innerEl.height() < this.options.restoreHeight) { innerEl.css("max-height", (Math.min(docH - parseInt(menuRoot.css("padding-top")) - parseInt(menuRoot.css("padding-bottom")) - 5, this.options.restoreHeight)) + "px"); menuH = menuRoot.outerHeight(); if (top + menuH > docH) { menuRoot.css("top", 0); } if (this.allowScrollbar) { this.scroller.update({ minScrollbarLength: 40 }); } } } } }); $(document).on("keydown.bs.dropdown.data-api", "[data-toggle=dropdown], [role=menu]", function (e) { if (e.keyCode !== Common.UI.Keys.UP && e.keyCode !== Common.UI.Keys.DOWN && e.keyCode !== Common.UI.Keys.LEFT && e.keyCode !== Common.UI.Keys.RIGHT && e.keyCode !== Common.UI.Keys.RETURN) { return; } _.defer(function () { var target = $(e.target).closest(".dropdown-toggle"); target.parent().find(".inner.canfocused").trigger("dataview:keydown", e); }, 100); }); });