Merge pull request 'feature/paste-options' (#975) from feature/paste-options into release/v9.3.0

Reviewed-on: https://git.onlyoffice.com/ONLYOFFICE/web-apps/pulls/975
This commit is contained in:
Maxim Kadushkin
2026-02-13 08:28:48 +00:00
5 changed files with 310 additions and 6 deletions

View File

@ -3980,6 +3980,7 @@ define([], function () {
pasteContainer = documentHolderView.cmpEl.find('#special-paste-container'),
pasteItems = specialPasteShowOptions.asc_getOptions(),
isTable = !!specialPasteShowOptions.asc_getContainTables();
if (!pasteItems) return;
// Prepare menu container
@ -4072,8 +4073,26 @@ define([], function () {
});
}
}
(menu.items.length>0) && menu.items[0].setChecked(true, true);
var lastSelected = specialPasteShowOptions.asc_getLastSelectedPasteProperty();
(menu.items.length>0) && !lastSelected && menu.items[0].setChecked(true, true);
me._state.lastSpecPasteChecked = (menu.items.length>0) ? menu.items[0] : null;
if (lastSelected) {
var foundItem = null;
if (me.btnSpecialPaste && me.btnSpecialPaste.menu && me.btnSpecialPaste.menu.items.length > 0) {
for (var i = 0; i < me.btnSpecialPaste.menu.items.length; i++) {
var menuItem = me.btnSpecialPaste.menu.items[i];
if (menuItem.value === lastSelected) {
foundItem = menuItem;
break;
}
}
}
if (foundItem) {
foundItem.setChecked(true, true);
// me._state.lastSpecPasteChecked = foundItem;
}
}
if (importText) {
menu.addItem(new Common.UI.MenuItem({ caption: '--' }));
@ -4236,7 +4255,7 @@ define([], function () {
}
str = str.substring(0, str.length-1)
var keymap = {};
keymap[str] = _.bind(function(e) {
keymap[str + ' ' + 'special-paste-context'] = _.bind(function(e) {
var menu = this.btnSpecialPaste.menu;
for (var i = 0; i < menu.items.length; i++) {
if (this.hkSpecPaste[menu.items[i].value] === String.fromCharCode(e.keyCode)) {
@ -4245,14 +4264,16 @@ define([], function () {
}
}, me);
Common.util.Shortcuts.delegateShortcuts({shortcuts:keymap});
Common.util.Shortcuts.suspendEvents(str, undefined, true);
Common.util.Shortcuts.suspendEvents(str, 'special-paste-context', true);
var pasteContainer = me.documentHolder.cmpEl.find('#special-paste-container');
me.btnSpecialPaste.menu.on('show:after', function(menu) {
Common.util.Shortcuts.resumeEvents(str);
window.key.setScope('special-paste-context');
Common.util.Shortcuts.resumeEvents(str, 'special-paste-context');
pasteContainer.addClass('has-open-menu');
}).on('hide:after', function(menu) {
Common.util.Shortcuts.suspendEvents(str, undefined, true);
window.key.setScope('all');
Common.util.Shortcuts.suspendEvents(str, 'special-paste-context', true);
pasteContainer.removeClass('has-open-menu');
});
};

View File

@ -483,6 +483,20 @@ define([
toolbar.cmbNumberFormat.cmpEl.on('click', '#id-toolbar-mnu-item-more-formats a', _.bind(this.onNumberFormatSelect, this));
toolbar.btnCurrencyStyle.menu.on('item:click', _.bind(this.onNumberFormatMenu, this));
$('#id-toolbar-menu-new-bordercolor').on('click', _.bind(this.onNewBorderColor, this));
$('#slot-btn-paste').on('click', '.dropdown-toggle', _.bind(function(e) {
e.preventDefault();
e.stopImmediatePropagation();
var menu = this.toolbar.btnPaste.menu;
if (menu && menu.isVisible && menu.isVisible()) {
menu.hide();
return;
}
this.onBtnPasteOptionsClick();
}, this));
// toolbar.btnPaste.menu && toolbar.btnPaste.menu.on('show:before', _.bind(this.onBtnPasteOptionsClick, this));
toolbar.btnPageOrient.menu.on('item:click', _.bind(this.onPageOrientSelect, this));
toolbar.btnPageMargins.menu.on('item:click', _.bind(this.onPageMarginsSelect, this));
toolbar.mnuPageSize.on('item:click', _.bind(this.onPageSizeClick, this));
@ -1051,6 +1065,242 @@ define([
Common.component.Analytics.trackEvent('ToolBar', 'Table');
},
onBtnPasteOptionsClick: function (btn, e) {
var me = this;
var menu = me.toolbar.btnPaste.menu;
if (menu && menu.items && menu.items.length > 0) {
for (var i = 0; i < menu.items.length; i++) {
menu.removeItem(menu.items[i]);
i--;
}
}
this.api.asc_getPasteOptions(function (options) {
me.handlePasteOptions(options)
});
},
handlePasteOptions: function (options) {
var me = this;
if (options === null) {
var menu = me.toolbar.btnPaste.menu;
var mnu = new Common.UI.MenuItem({
caption: me.txtPasteNoOptions,
disabled: true
});
menu.addItem(mnu)
menu.show();
return
}
var pasteItems = options.asc_getOptions(),
isTable = !!options.asc_getContainTables();
if (!pasteItems) return;
me._arrSpecialPaste = [];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.paste] = [me.txtPaste, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.pasteOnlyFormula] = [me.txtPasteFormulas, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.formulaNumberFormat] = [me.txtPasteFormulaNumFormat, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.formulaAllFormatting] = [me.txtPasteKeepSourceFormat, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.formulaWithoutBorders] = [me.txtPasteBorders, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.formulaColumnWidth] = [me.txtPasteColWidths, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.mergeConditionalFormating] = [me.txtPasteMerge, 0];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.pasteOnlyValues] = [me.txtPasteValues, 1];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.valueNumberFormat] = [me.txtPasteValNumFormat, 1];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.valueAllFormating] = [me.txtPasteValFormat, 1];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.pasteOnlyFormating] = [me.txtPasteFormat, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.link] = [me.txtPasteLink, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.transpose] = [me.txtPasteTranspose, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.picture] = [me.txtPastePicture, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.linkedPicture] = [me.txtPasteLinkPicture, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.sourceformatting] = [me.txtPasteSourceFormat, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.destinationFormatting] = [me.txtPasteDestFormat, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.keepTextOnly] = [me.txtKeepTextOnly, 2];
me._arrSpecialPaste[Asc.c_oSpecialPasteProps.useTextImport] = [me.txtUseTextImport, 3];
me.initSpecialPasteEvents();
if (pasteItems.length>0) {
var menu = me.toolbar.btnPaste.menu;
var groups = [];
for (var i = 0; i < 3; i++) {
groups[i] = [];
}
var importText, pasteItem;
_.each(pasteItems, function(menuItem, index) {
if (me._arrSpecialPaste[menuItem]) {
var mnu = new Common.UI.MenuItem({
caption: me._arrSpecialPaste[menuItem][0] + (me.hkSpecPaste[menuItem] ? ' (' + me.hkSpecPaste[menuItem] + ')' : ''),
value: menuItem,
checkable: true,
toggleGroup: 'specialPasteGroup'
}).on('click', _.bind(me.onSpecialPasteItemClick, me));
if (menuItem == Asc.c_oSpecialPasteProps.paste) {
pasteItem = mnu;
} else if (menuItem == Asc.c_oSpecialPasteProps.useTextImport) {
importText = mnu;
} else {
groups[me._arrSpecialPaste[menuItem][1]].push(mnu);
}
me._arrSpecialPaste[menuItem][2] = mnu;
}
});
var groupTitles = [me.txtFormula, me.txtValue, me.txtOther];
if (pasteItem) {
menu.addItem(pasteItem);
}
for (var i = 0; i < 3; i++) {
if (groups[i].length > 0) {
if (menu.items.length > 0) {
menu.addItem(new Common.UI.MenuItem({ caption: '--' }));
}
menu.addItem(new Common.UI.MenuItem({
header: groupTitles[i],
disabled: true,
cls: 'menu-header'
}));
_.each(groups[i], function (menuItem, index) {
menu.addItem(menuItem);
});
}
}
if (importText) {
menu.addItem(new Common.UI.MenuItem({ caption: '--' }));
menu.addItem(importText);
}
if (menu.items.length>0 && options.asc_getShowPasteSpecial()) {
menu.addItem(new Common.UI.MenuItem({ caption: '--' }));
var mnu = new Common.UI.MenuItem({
caption: me.textPasteSpecial,
value: 'special'
}).on('click', function(item, e) {
(new SSE.Views.SpecialPasteDialog({
props: pasteItems,
isTable: isTable,
handler: function (result, settings) {
if (result == 'ok') {
if (me && me.api) {
me.api.asc_SpecialPaste(settings, true);
}
}
}
})).show();
setTimeout(function(){menu.hide();}, 100);
});
menu.addItem(mnu);
}
menu.show();
}
},
onSpecialPasteItemClick: function (item, e) {
var me = this,
menu = this.toolbar.btnPaste.menu;
if (item.value == Asc.c_oSpecialPasteProps.useTextImport) {
(new Common.Views.OpenDialog({
title: me.txtImportWizard,
closable: true,
type: Common.Utils.importTextType.Paste,
preview: true,
api: me.api,
handler: function (result, settings) {
if (result == 'ok') {
if (me && me.api) {
var props = new Asc.SpecialPasteProps();
props.asc_setProps(Asc.c_oSpecialPasteProps.useTextImport);
props.asc_setAdvancedOptions(settings.textOptions);
me.api.asc_SpecialPaste(props, true);
}
}
}
})).show();
setTimeout(function(){menu.hide();}, 100);
} else {
var props = new Asc.SpecialPasteProps();
props.asc_setProps(item.value);
me.api.asc_SpecialPaste(props, true);
setTimeout(function(){menu.hide();}, 100);
}
return false;
},
initSpecialPasteEvents: function() {
if (this.specialPasteEventsInited) return
var me = this;
me.hkSpecPaste = [];
me.hkSpecPaste[Asc.c_oSpecialPasteProps.paste] = 'P';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.pasteOnlyFormula] = 'F';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.formulaNumberFormat] = 'O';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.formulaAllFormatting] = 'K';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.formulaWithoutBorders] = 'B';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.formulaColumnWidth] = 'W';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.mergeConditionalFormating] = 'G';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.transpose] = 'T';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.pasteOnlyValues] = 'V';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.valueNumberFormat] = 'A';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.valueAllFormating] = 'E';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.pasteOnlyFormating] = 'R';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.link] = 'N';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.picture] = 'U';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.linkedPicture] = 'I';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.sourceformatting] = 'K';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.destinationFormatting] = 'M';
me.hkSpecPaste[Asc.c_oSpecialPasteProps.keepTextOnly] = 'T';
// me.hkSpecPaste[Asc.c_oSpecialPasteProps.useTextImport] = '';
var str = '';
for(var key in me.hkSpecPaste){
if(me.hkSpecPaste.hasOwnProperty(key)){
if (str.indexOf(me.hkSpecPaste[key])<0)
str += me.hkSpecPaste[key] + ',';
}
}
str = str.substring(0, str.length-1)
var keymap = {};
keymap[str + ' ' + 'special-paste-toolbar'] = _.bind(function(e) {
var menu = this.toolbar.btnPaste.menu;
for (var i = 0; i < menu.items.length; i++) {
if (this.hkSpecPaste[menu.items[i].value] === String.fromCharCode(e.keyCode)) {
return me.onSpecialPasteItemClick({value: menu.items[i].value});
}
}
}, me);
Common.util.Shortcuts.delegateShortcuts({shortcuts:keymap});
window.key.setScope('special-paste-toolbar');
var closeMenuOnWindowBlur = function() {
if (me.toolbar.btnPaste.menu.$el && me.toolbar.btnPaste.menu.$el.is(':visible')) {
me.toolbar.btnPaste.menu.hide();
}
};
$(window).on('blur.pastemenuhide', closeMenuOnWindowBlur);
me.toolbar.btnPaste.menu.on('show:after', function(menu) {
window.key.setScope('special-paste-toolbar');
Common.util.Shortcuts.resumeEvents(str);
$(window).on('blur.pastemenuhide', closeMenuOnWindowBlur);
}).on('hide:after', function(menu) {
window.key.setScope('all');
Common.util.Shortcuts.suspendEvents(str, undefined, true);
$(window).off('blur.pastemenuhide', closeMenuOnWindowBlur);
});
this.specialPasteEventsInited = true;
},
onInsertImageMenu: function(menu, item, e) {
var me = this;
if (item.value === 'file') {

View File

@ -18,7 +18,7 @@
<div class="group small">
<div class="elset">
<span class="btn-slot split" id="slot-btn-copy"></span>
<span class="btn-slot" id="slot-btn-paste"></span>
<span class="btn-slot split" id="slot-btn-paste"></span>
</div>
<div class="elset">
<span class="btn-slot split" id="slot-btn-undo"></span>

View File

@ -203,6 +203,8 @@ define([
applyLayout: function (config) {
var me = this;
me.config = config;
function dummyCmp() {
return {
isDummy : true,
@ -231,6 +233,8 @@ define([
iconCls : 'toolbar__icon btn-paste',
lock : [/*_set.editCell,*/ _set.coAuth, _set.lostConnect, _set.editVisibleArea, _set.userProtected, _set.externalChartProtected],
dataHint : '1',
menu: config.isDesktopApp ? new Common.UI.Menu({items: []}) : false,
split: config.isDesktopApp,
dataHintDirection: (config.isEditDiagram || config.isEditMailMerge || config.isEditOle) ? 'bottom' : 'top',
dataHintTitle: 'V'
});
@ -2589,6 +2593,10 @@ define([
Common.Utils.injectComponent($host.find(id), cmp);
};
if (!this.config || !this.config.isDesktopApp) {
$host.find('#slot-btn-paste').removeClass('split');
}
_injectComponent('#slot-field-fontname', this.cmbFontName);
_injectComponent('#slot-field-fontsize', this.cmbFontSize);
_injectComponent('#slot-btn-print', this.btnPrint);

View File

@ -2416,6 +2416,31 @@
"SSE.Controllers.Toolbar.warnLongOperation": "The operation you are about to perform might take rather much time to complete.<br>Are you sure you want to continue?",
"SSE.Controllers.Toolbar.warnMergeLostData": "Only the data from the upper-left cell will remain in the merged cell. <br>Are you sure you want to continue?",
"SSE.Controllers.Toolbar.warnNoRecommended": "To create a chart, select the cells that contain the data you'd like to use.<br>If you have names for the rows and columns and you'd like use them as labels, include them in your selection.",
"SSE.Controllers.Toolbar.txtKeepTextOnly": "Keep text only",
"SSE.Controllers.Toolbar.txtUseTextImport": "Use text import",
"SSE.Controllers.Toolbar.txtPaste": "Paste",
"SSE.Controllers.Toolbar.txtPasteNoOptions": "Paste (P)",
"SSE.Controllers.Toolbar.txtPasteBorders": "Formula without borders",
"SSE.Controllers.Toolbar.txtPasteColWidths": "Formula + column width",
"SSE.Controllers.Toolbar.txtPasteDestFormat": "Destination formatting",
"SSE.Controllers.Toolbar.txtPasteFormat": "Paste only formatting",
"SSE.Controllers.Toolbar.txtPasteFormulaNumFormat": "Formula + number format",
"SSE.Controllers.Toolbar.txtPasteFormulas": "Paste only formula",
"SSE.Controllers.Toolbar.txtPasteKeepSourceFormat": "Formula + all formatting",
"SSE.Controllers.Toolbar.txtPasteLink": "Paste link",
"SSE.Controllers.Toolbar.txtPasteLinkPicture": "Linked picture",
"SSE.Controllers.Toolbar.txtPasteMerge": "Merge conditional formatting",
"SSE.Controllers.Toolbar.txtPastePicture": "Picture",
"SSE.Controllers.Toolbar.txtPasteSourceFormat": "Source formatting",
"SSE.Controllers.Toolbar.txtPasteTranspose": "Transpose",
"SSE.Controllers.Toolbar.txtPasteValFormat": "Value + all formatting",
"SSE.Controllers.Toolbar.txtPasteValNumFormat": "Value + number format",
"SSE.Controllers.Toolbar.txtPasteValues": "Paste only value",
"SSE.Controllers.Toolbar.txtOther": "Other",
"SSE.Controllers.Toolbar.txtFormula": "Formula",
"SSE.Controllers.Toolbar.txtValue": "Value",
"SSE.Controllers.Toolbar.textPasteSpecial": "Paste special",
"SSE.Controllers.Toolbar.txtImportWizard": "Text Import",
"SSE.Controllers.Viewport.textFreezePanes": "Freeze panes",
"SSE.Controllers.Viewport.textFreezePanesShadow": "Show Frozen Panes Shadow",
"SSE.Controllers.Viewport.textHideFBar": "Hide Formula Bar",