From 23df51e17ece7470ace2c016d00d558a0c546556 Mon Sep 17 00:00:00 2001 From: JuliaSvinareva Date: Fri, 8 Oct 2021 18:21:56 +0300 Subject: [PATCH] [PE] Add ComboDataViewShape component (bug 43485) --- .../main/lib/component/ComboDataViewShape.js | 383 ++++++++++++++++++ .../main/resources/less/combo-dataview.less | 6 +- apps/common/main/resources/less/dataview.less | 2 +- apps/common/main/resources/less/toolbar.less | 24 ++ .../main/app/controller/Toolbar.js | 11 +- .../main/app/template/Toolbar.template | 2 +- .../main/app/view/Toolbar.js | 33 +- 7 files changed, 452 insertions(+), 9 deletions(-) create mode 100644 apps/common/main/lib/component/ComboDataViewShape.js diff --git a/apps/common/main/lib/component/ComboDataViewShape.js b/apps/common/main/lib/component/ComboDataViewShape.js new file mode 100644 index 000000000..824db66a6 --- /dev/null +++ b/apps/common/main/lib/component/ComboDataViewShape.js @@ -0,0 +1,383 @@ +/* + * + * (c) Copyright Ascensio System SIA 2010-2019 + * + * 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 20A-12 Ernesta Birznieka-Upisha + * street, Riga, Latvia, EU, LV-1050. + * + * 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 + * +*/ +/** + * ComboDataView.js + * + * Created by Julia Svinareva on 6/10/21 + * Copyright (c) 2021 Ascensio System SIA. All rights reserved. + * + */ + +if (Common === undefined) + var Common = {}; + +define([ + 'common/main/lib/component/BaseView', + 'common/main/lib/component/DataView' +], function () { + 'use strict'; + + Common.UI.ComboDataViewShape = Common.UI.BaseView.extend({ + options : { + id : null, + cls : '', + style : '', + hint : false, + itemWidth : 80, + itemHeight : 40, + menuMaxHeight : 300, + enableKeyEvents : false, + additionalMenuItems : null, + minWidth: -1, + dataHint: '', + dataHintDirection: '', + dataHintOffset: '' + }, + + template: _.template([ + '
', + '
', + '
', + '
' + ].join('')), + + initialize : function(options) { + Common.UI.BaseView.prototype.initialize.call(this, options); + + this.id = this.options.id || Common.UI.getId(); + this.cls = this.options.cls; + this.style = this.options.style; + this.hint = this.options.hint; + this.store = this.options.store || new Common.UI.DataViewStore(); + this.itemWidth = this.options.itemWidth; + this.itemHeight = this.options.itemHeight; + this.menuMaxHeight = this.options.menuMaxHeight; + this.menuWidth = this.options.menuWidth; + this.rootWidth = 0; + this.rootHeight = 0; + this.rendered = false; + this.needFillComboView = false; + this.minWidth = this.options.minWidth; + this.delayRenderTips = this.options.delayRenderTips || false; + + this.fieldPicker = new Common.UI.DataView({ + cls: 'field-picker', + allowScrollbar: false, + itemTemplate: _.template('
\">
'), + delayRenderTips: this.delayRenderTips + }); + + this.openButton = new Common.UI.Button({ + cls: 'open-menu', + menu: new Common.UI.Menu({ + cls: 'menu-insert-shape', + menuAlign: 'tl-tl', + offset: [0, 3], + items: [ + {template: _.template('')} + ] + }), + dataHint: this.options.dataHint, + dataHintDirection: this.options.dataHintDirection, + dataHintOffset: this.options.dataHintOffset + }); + + // Handle resize + setInterval(_.bind(this.checkSize, this), 500); + + if (this.options.el) { + this.render(); + } + }, + + fillComboView: function (collection) { + var newStyles = [], + store = collection.at(0).get('groupStore'); + for(var i = 0; i < 12; i ++) { + newStyles.push(store.at(i)); + } + + this.fieldPicker.store.reset(newStyles); + + this.fieldPicker.on('item:select', _.bind(this.onFieldPickerSelect, this)); + this.fieldPicker.on('item:click', _.bind(this.onFieldPickerClick, this)); + this.fieldPicker.on('item:contextmenu', _.bind(this.onPickerItemContextMenu, this)); + this.fieldPicker.el.addEventListener('contextmenu', _.bind(this.onPickerComboContextMenu, this), false); + }, + + setMenuPicker: function (collection, recent, text) { + this.menuPicker = new Common.UI.DataViewShape({ + el: this.cmpEl.find('.menu-picker-container'), + cls: 'menu-picker', + parentMenu: this.openButton.menu, + restoreHeight: this.menuMaxHeight, + style: 'max-height: '+this.menuMaxHeight+'px;', + itemTemplate : _.template('
\">
'), + groups: collection, + textRecentlyUsed: text, + recentShapes: recent + }); + + this.menuPicker.on('item:select', _.bind(this.onMenuPickerSelect, this)); + this.menuPicker.on('item:click', _.bind(this.onMenuPickerClick, this)); + this.menuPicker.on('item:contextmenu', _.bind(this.onPickerItemContextMenu, this)); + this.menuPicker.el.addEventListener('contextmenu', _.bind(this.onPickerComboContextMenu, this), false); + + this.onResize(); + }, + + render: function(parentEl) { + if (!this.rendered) { + var me = this; + + me.trigger('render:before', me); + + me.cmpEl = me.$el || $(me.el); + + var templateEl = me.template({ + id : me.id, + cls : me.cls, + style : me.style + }); + + if (parentEl) { + me.setElement(parentEl, false); + + me.cmpEl = $(templateEl); + + parentEl.html(me.cmpEl); + } else { + me.cmpEl.html(templateEl); + } + + me.rootWidth = me.cmpEl.width(); + me.rootHeight = me.cmpEl.height(); + + me.fieldPicker.render($('.view', me.cmpEl)); + me.openButton.render($('.button', me.cmpEl)); + //me.menuPicker.render($('.menu-picker-container', me.cmpEl)); + + if (me.openButton.menu.cmpEl) { + if (me.openButton.menu.cmpEl) { + me.openButton.menu.menuAlignEl = me.cmpEl; + me.openButton.menu.cmpEl.css('min-width', me.itemWidth); + me.openButton.menu.on('show:before', _.bind(me.onBeforeShowMenu, me)); + me.openButton.menu.on('show:after', _.bind(me.onAfterShowMenu, me)); + me.openButton.cmpEl.on('hide.bs.dropdown', _.bind(me.onBeforeHideMenu, me)); + me.openButton.cmpEl.on('hidden.bs.dropdown', _.bind(me.onAfterHideMenu, me)); + } + } + + if (me.options.hint) { + me.cmpEl.attr('data-toggle', 'tooltip'); + me.cmpEl.tooltip({ + title : me.options.hint, + placement : me.options.hintAnchor || 'cursor' + }); + } + + //me.onResize(); + + me.rendered = true; + + me.trigger('render:after', me); + } + if (this.disabled) { + this.setDisabled(!!this.disabled); + } + + return this; + }, + + checkSize: function() { + if (this.cmpEl && this.cmpEl.is(':visible')) { + var me = this, + width = this.cmpEl.width(), + height = this.cmpEl.height(); + + if (width < this.minWidth) return; + + if (this.rootWidth != width || this.rootHeight != height) { + this.rootWidth = width; + this.rootHeight = height; + setTimeout(function() { + me.openButton.menu.cmpEl.outerWidth(); + me.rootWidth = me.cmpEl.width(); + }, 10); + this.onResize(); + } + } + }, + + onResize: function() { + if (this.openButton) { + var button = $('button', this.openButton.cmpEl); + var cntButton = $('.button', this.cmpEl); + button && cntButton.width() > 0 && button.css({ + width : cntButton.width(), + height: cntButton.height() + }); + + this.openButton.menu.hide(); + + /*var picker = this.menuPicker; + if (picker) { + var record = picker.getSelectedRec(); + this.fillComboView(record || picker.store.at(0), !!record, true); + + picker.onResize(); + }*/ + } + + if (!this.isSuspendEvents) + this.trigger('resize', this); + }, + + onBeforeShowMenu: function(e) { + var menu = this.openButton.menu; + if (menu.cmpEl) { + menu.menuAlignEl = this.cmpEl; + var offset = this.cmpEl.width() - this.openButton.$el.width() - this.menuWidth + 1; + menu.setOffset(Math.min(offset, 0)); + } + + if (this.options.hint) { + var tip = this.cmpEl.data('bs.tooltip'); + if (tip) { + if (tip.dontShow===undefined) + tip.dontShow = true; + tip.hide(); + } + } + }, + + onBeforeHideMenu: function(e) { + this.trigger('hide:before', this, e); + + if (Common.UI.Scroller.isMouseCapture()) + e.preventDefault(); + + if (this.isStylesNotClosable) + return false; + }, + + onAfterShowMenu: function(e) { + var me = this; + if (me.menuPicker.scroller) { + me.menuPicker.scroller.update({ + includePadding: true, + suppressScrollX: true, + alwaysVisibleY: true + }); + } + }, + + onAfterHideMenu: function(e, isFromInputControl) { + this.menuPicker.selectedBeforeHideRec = this.menuPicker.getSelectedRec(); // for DataView - onKeyDown - Return key + this.menuPicker.deselectAll(); + this.trigger('hide:after', this, e, isFromInputControl); + }, + + onFieldPickerSelect: function(picker, item, record) { + // + }, + + onMenuPickerSelect: function(picker, item, record, fromKeyDown) { + this.needFillComboView = this.disabled; + if (this.disabled || fromKeyDown===true) return; + + /*this.fillComboView(record, false); + if (record && !this.isSuspendEvents) + this.trigger('select', this, record);*/ + }, + + onFieldPickerClick: function(dataView, itemView, record) { + if (this.disabled) return; + + if (!this.isSuspendEvents) + this.trigger('click', this, record); + + if (this.options.hint) { + var tip = this.cmpEl.data('bs.tooltip'); + if (tip) { + if (tip.dontShow===undefined) + tip.dontShow = true; + tip.hide(); + } + } + + this.fieldPicker.deselectAll(); + }, + + onMenuPickerClick: function(dataView, itemView, record) { + if (this.disabled) return; + + if (!this.isSuspendEvents) + this.trigger('click', this, record); + }, + + onPickerItemContextMenu: function(dataView, itemView, record, e) { + if (this.disabled) return; + + if (!this.isSuspendEvents) { + this.trigger('contextmenu', this, record, e); + } + e.preventDefault(); + e.stopPropagation(); + return false; + }, + + onPickerComboContextMenu: function(mouseEvent) { + if (this.disabled) return; + + if (!this.isSuspendEvents) { + this.trigger('contextmenu', this, undefined, mouseEvent); + } + }, + + setDisabled: function(disabled) { + this.disabled = disabled; + + if (!this.rendered) + return; + + this.cmpEl.toggleClass('disabled', disabled); + $('button', this.openButton.cmpEl).toggleClass('disabled', disabled); + this.fieldPicker.setDisabled(disabled); + }, + + isDisabled: function() { + return this.disabled; + } + }) +}); \ No newline at end of file diff --git a/apps/common/main/resources/less/combo-dataview.less b/apps/common/main/resources/less/combo-dataview.less index e7f4ccf9a..b5b25eab2 100644 --- a/apps/common/main/resources/less/combo-dataview.less +++ b/apps/common/main/resources/less/combo-dataview.less @@ -98,7 +98,7 @@ } } - .item { + &:not('.shapes') .item { padding: 2px; border: @scaled-one-px-value-ie solid @border-regular-control-ie; border: @scaled-one-px-value solid @border-regular-control; @@ -123,7 +123,7 @@ } } - &.disabled { + &.disabled:not('.shapes') { .item { &:hover:not(.selected) { .box-shadow(none); @@ -135,7 +135,7 @@ } } - .dropdown-menu { + &:not('.shapes') .dropdown-menu { box-sizing: content-box; padding: 0; border-top-left-radius: 0; diff --git a/apps/common/main/resources/less/dataview.less b/apps/common/main/resources/less/dataview.less index 7acb0bcdb..19189ea31 100644 --- a/apps/common/main/resources/less/dataview.less +++ b/apps/common/main/resources/less/dataview.less @@ -92,7 +92,7 @@ .menu-insert-shape, .menu-change-shape { width: 362px; - padding: 10px 5px 10px 10px; + padding: 10px 5px 10px 10px !important; .group-description { padding: 3px 0 3px 4px; } diff --git a/apps/common/main/resources/less/toolbar.less b/apps/common/main/resources/less/toolbar.less index 838c7b622..5c40cf8b7 100644 --- a/apps/common/main/resources/less/toolbar.less +++ b/apps/common/main/resources/less/toolbar.less @@ -567,6 +567,30 @@ } } +#slot-combo-insertshape { + width: 150px; + height: 46px; + .view { + padding-right: 14px; + } + .dataview.field-picker { + height: 100%; + margin: 0; + padding: 2px; + .item { + margin: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + } + .button { + width: 14px; + .caret { + width: 4px; + height: 4px; + } + } +} .item-shape { .icon { diff --git a/apps/presentationeditor/main/app/controller/Toolbar.js b/apps/presentationeditor/main/app/controller/Toolbar.js index 11219b260..347a24fea 100644 --- a/apps/presentationeditor/main/app/controller/Toolbar.js +++ b/apps/presentationeditor/main/app/controller/Toolbar.js @@ -2034,14 +2034,21 @@ define([ }, onResetAutoshapes: function () { - var me = this; + var me = this, + collection = PE.getCollection('ShapeGroups'); var onShowBefore = function(menu) { - me.toolbar.updateAutoshapeMenu(menu, PE.getCollection('ShapeGroups')); + me.toolbar.updateAutoshapeMenu(menu, collection); menu.off('show:before', onShowBefore); }; me.toolbar.btnsInsertShape.forEach(function (btn, index) { btn.menu.on('show:before', onShowBefore); }); + var onComboShowBefore = function (menu) { + me.toolbar.updateComboAutoshapeMenu(collection); + menu.off('show:before', onComboShowBefore); + } + me.toolbar.cmbInsertShape.openButton.menu.on('show:before', onComboShowBefore); + me.toolbar.cmbInsertShape.fillComboView(collection); }, onResetSlides: function () { diff --git a/apps/presentationeditor/main/app/template/Toolbar.template b/apps/presentationeditor/main/app/template/Toolbar.template index 14e7722d5..924f83a62 100644 --- a/apps/presentationeditor/main/app/template/Toolbar.template +++ b/apps/presentationeditor/main/app/template/Toolbar.template @@ -117,9 +117,9 @@ - +
diff --git a/apps/presentationeditor/main/app/view/Toolbar.js b/apps/presentationeditor/main/app/view/Toolbar.js index 3252c4cc0..850296a6a 100644 --- a/apps/presentationeditor/main/app/view/Toolbar.js +++ b/apps/presentationeditor/main/app/view/Toolbar.js @@ -56,7 +56,8 @@ define([ 'common/main/lib/component/ComboBoxFonts', 'common/main/lib/component/ComboDataView' ,'common/main/lib/component/SynchronizeTip' - ,'common/main/lib/component/Mixtbar' + ,'common/main/lib/component/Mixtbar', + 'common/main/lib/component/ComboDataViewShape' ], function (Backbone, template, template_view) { 'use strict'; @@ -1051,6 +1052,19 @@ define([ '
' ].join('')); + this.cmbInsertShape = new Common.UI.ComboDataViewShape({ + cls: 'combo-styles shapes', + itemWidth: 20, + itemHeight: 20, + menuMaxHeight: 640, + menuWidth: 362, + enableKeyEvents: true, + lock: [PE.enumLock.slideDeleted, PE.enumLock.lostConnect, PE.enumLock.noSlides, PE.enumLock.disableOnStart], + dataHint: '1', + dataHintDirection: 'bottom', + dataHintOffset: '-16, 0' + }); + this.lockControls = [this.btnChangeSlide, this.btnSave, this.btnCopy, this.btnPaste, this.btnUndo, this.btnRedo, this.cmbFontName, this.cmbFontSize, this.btnIncFontSize, this.btnDecFontSize, this.btnBold, this.btnItalic, this.btnUnderline, this.btnStrikeout, this.btnSuperscript, this.btnChangeCase, this.btnHighlightColor, @@ -1193,6 +1207,7 @@ define([ _injectComponent('#slot-btn-editheader', this.btnEditHeader); _injectComponent('#slot-btn-datetime', this.btnInsDateTime); _injectComponent('#slot-btn-slidenum', this.btnInsSlideNum); + _injectComponent('#slot-combo-insertshape', this.cmbInsertShape); this.btnInsAudio && _injectComponent('#slot-btn-insaudio', this.btnInsAudio); this.btnInsVideo && _injectComponent('#slot-btn-insvideo', this.btnInsVideo); @@ -1711,6 +1726,7 @@ define([ menuShape.addItem(menuitem); var recents = Common.localStorage.getItem('pe-recent-shapes'); + recents = recents ? JSON.parse(recents) : null; var shapePicker = new Common.UI.DataViewShape({ el: $('#id-toolbar-menu-insertshape-'+index), @@ -1719,13 +1735,26 @@ define([ parentMenu: menuShape, restoreHeight: 640, textRecentlyUsed: me.textRecentlyUsed, - recentShapes: recents ? JSON.parse(recents) : null + recentShapes: recents }); shapePicker.on('item:click', function(picker, item, record, e) { if (e.type !== 'click') Common.UI.Menu.Manager.hideAll(); if (record) me.fireEvent('insert:shape', [record.get('data').shapeType]); }); + + }, + + updateComboAutoshapeMenu: function (collection) { + var me = this, + recents = Common.localStorage.getItem('pe-recent-shapes'); + recents = recents ? JSON.parse(recents) : null; + me.cmbInsertShape.setMenuPicker(collection, recents, me.textRecentlyUsed); + me.cmbInsertShape.on('click', function (btn, record) { + if (record) { + me.fireEvent('insert:shape', [record.get('data').shapeType]); + } + }); }, updateAddSlideMenu: function(collection) {