mirror of
https://github.com/ONLYOFFICE/web-apps.git
synced 2026-04-07 14:06:16 +08:00
Merge pull request 'feature/tab-inline-rename' (#563) from feature/tab-inline-rename into develop
This commit is contained in:
@ -156,7 +156,7 @@ define([
|
||||
'</div>' +
|
||||
'<div class="lr-separator" id="id-box-doc-name">' +
|
||||
// '<label id="title-doc-name" /></label>' +
|
||||
'<input id="title-doc-name" autofill="off" autocomplete="off"/></input>' +
|
||||
'<input id="title-doc-name" autofill="off" autocomplete="off" spellcheck="false"/></input>' +
|
||||
'</div>' +
|
||||
'<div class="hedset">' +
|
||||
'<div class="btn-slot" data-layout-name="header-user">' +
|
||||
|
||||
@ -81,11 +81,21 @@ define([
|
||||
},
|
||||
|
||||
onLaunch: function() {
|
||||
this.statusbar = this.createView('Statusbar').render();
|
||||
this.statusbar = this.createView('Statusbar', { controller: this }).render();
|
||||
this.statusbar.$el.css('z-index', 10);
|
||||
this.statusbar.labelZoom.css('min-width', 80);
|
||||
this.statusbar.labelZoom.text(Common.Utils.String.format(this.zoomText, 100));
|
||||
this.statusbar.zoomMenu.on('item:click', _.bind(this.menuZoomClick, this));
|
||||
this.$measureSpan = $('<span>').css({
|
||||
position: 'absolute',
|
||||
visibility: 'hidden',
|
||||
whiteSpace: 'pre',
|
||||
top: 0,
|
||||
left: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
border: 'none'
|
||||
}).appendTo(document.body);
|
||||
|
||||
this.bindViewEvents(this.statusbar, this.events);
|
||||
|
||||
@ -194,7 +204,6 @@ define([
|
||||
this.api.asc_registerCallback('asc_generateNewSheetNames', _.bind(function (arrNames, callback) {
|
||||
callback(this.generateSheetNames(false, undefined, arrNames));
|
||||
}, this));
|
||||
|
||||
this.statusbar.setApi(api);
|
||||
},
|
||||
|
||||
@ -514,48 +523,182 @@ define([
|
||||
}
|
||||
},
|
||||
|
||||
renameWorksheet: function() {
|
||||
isAllowedChar(char) {
|
||||
return !/[:\\/*?\[\]]/.test(char);
|
||||
},
|
||||
|
||||
isValidWorksheetName(name) {
|
||||
return !/^'|'$/.test(name) && !/[:\\/*?\[\]]/.test(name);
|
||||
},
|
||||
|
||||
updateInputWidth($input, $tabEl) {
|
||||
this.$measureSpan.text($input.val() || ' ').css({
|
||||
fontWeight: $input.css('font-weight'),
|
||||
fontSize: $input.css('font-size'),
|
||||
fontFamily: $input.css('font-family'),
|
||||
letterSpacing: $input.css('letter-spacing'),
|
||||
lineHeight: $input.css('line-height'),
|
||||
fontStyle: $input.css('font-style'),
|
||||
fontVariant: $input.css('font-variant')
|
||||
});
|
||||
const width = this.$measureSpan.width();
|
||||
$input.width(width);
|
||||
$tabEl.width(width);
|
||||
},
|
||||
|
||||
showRenameError(message, $input) {
|
||||
var me = this;
|
||||
var wc = me.api.asc_getWorksheetsCount(), items = null;
|
||||
if (wc > 0) {
|
||||
var sindex = me.api.asc_getActiveWorksheetIndex();
|
||||
if (me.api.asc_isWorksheetLockedOrDeleted(sindex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value = Common.Utils.InternalSettings.get("sse-settings-coauthmode");
|
||||
if (!value) {
|
||||
items = [];
|
||||
while (wc--) {
|
||||
if (sindex !== wc) {
|
||||
items.push(me.api.asc_getWorksheetName(wc).toLowerCase());
|
||||
}
|
||||
_.defer(function() {
|
||||
Common.UI.error({
|
||||
msg: message,
|
||||
maxwidth: 600,
|
||||
callback: function() {
|
||||
_.delay(function() {
|
||||
me.isRenameErrorShown = false;
|
||||
$input.focus().select();
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
var tab = me.statusbar.tabbar.tabs[me.statusbar.tabbar.getActive()];
|
||||
var top = Common.Utils.getPosition(me.statusbar.$el).top - 115,
|
||||
left = Common.Utils.getOffset(tab.$el).left;
|
||||
|
||||
var current = me.api.asc_getWorksheetName(me.api.asc_getActiveWorksheetIndex());
|
||||
var win = (new SSE.Views.Statusbar.RenameDialog({
|
||||
current: current,
|
||||
names: items,
|
||||
api: me.api,
|
||||
handler: function (btn, s) {
|
||||
if (btn == 'ok' && s != current) {
|
||||
me.api.asc_renameWorksheet(s);
|
||||
}
|
||||
me.api.asc_enableKeyEvents(true);
|
||||
}
|
||||
}));
|
||||
if (typeof win.options.width == "number") {
|
||||
var bodywidth = $('body').width();
|
||||
if (left+win.options.width > bodywidth)
|
||||
left = bodywidth - win.options.width - 5;
|
||||
finishRename({ save, $input, $tabEl, tab, otherNames }) {
|
||||
const me = this;
|
||||
let newName = $input.val();
|
||||
const currentName = tab.label;
|
||||
if (save) {
|
||||
if (newName === '' || !me.isValidWorksheetName(newName)) {
|
||||
if (me.isRenameErrorShown) return false;
|
||||
me.isRenameErrorShown = true;
|
||||
me.showRenameError(this.errSheetNameRules, $input);
|
||||
return false;
|
||||
}
|
||||
win.show(left, top);
|
||||
if (otherNames.includes(newName.toLowerCase())) {
|
||||
if (me.isRenameErrorShown) return false;
|
||||
me.isRenameErrorShown = true;
|
||||
me.showRenameError(this.errNameExists, $input);
|
||||
return false;
|
||||
}
|
||||
if (newName !== currentName) {
|
||||
me.api.asc_renameWorksheet(newName);
|
||||
me.renameInputVal = null;
|
||||
me.renamingWorksheet = null;
|
||||
}
|
||||
} else {
|
||||
newName = currentName;
|
||||
}
|
||||
$input.remove();
|
||||
$tabEl.append(document.createTextNode(newName));
|
||||
$tabEl.attr('tabtitle', newName);
|
||||
tab.$el.attr('data-label', newName);
|
||||
me.renameInputCaret = null;
|
||||
return true;
|
||||
},
|
||||
|
||||
createRenameInput(currentName) {
|
||||
return $('<input type="text" class="inline-rename" maxlength="31" spellcheck="false"/>').val(currentName).css({
|
||||
color: 'inherit',
|
||||
backgroundColor: 'transparent',
|
||||
boxSizing: 'border-box',
|
||||
padding: 0,
|
||||
height: '80%',
|
||||
border: 'none',
|
||||
letterSpacing: '0.01em',
|
||||
fontSize: 'inherit',
|
||||
fontFamily: 'inherit',
|
||||
outline: 'none',
|
||||
margin: 0,
|
||||
lineHeight: 'inherit',
|
||||
cursor: 'text'
|
||||
});
|
||||
},
|
||||
|
||||
bindRenameEvents($input, $tabEl, tab, currentName, otherNames, originalWidth) {
|
||||
const me = this;
|
||||
|
||||
$input.on('keypress', function(e) {
|
||||
const char = String.fromCharCode(e.which || e.keyCode);
|
||||
if (!me.isAllowedChar(char) && !e.ctrlKey && !e.metaKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
$input.on('input', function() {
|
||||
me.renameInputVal = $input.val();
|
||||
me.renameInputCaret = $input[0].selectionStart;
|
||||
me.updateInputWidth($input, $tabEl);
|
||||
me.onWindowResize();
|
||||
});
|
||||
|
||||
$input.on('blur', function(e) {
|
||||
if (!me.isRenameErrorShown) {
|
||||
me.renamingWorksheet = null;
|
||||
me.finishRename({ save: true, $input, $tabEl, tab, otherNames });
|
||||
}
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$input.on('keydown', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
me.renamingWorksheet = null;
|
||||
me.finishRename({ save: true, $input, $tabEl, tab, otherNames });
|
||||
} else if (e.key === 'Escape') {
|
||||
me.renamingWorksheet = null;
|
||||
me.finishRename({ save: false, $input, $tabEl, tab, otherNames });
|
||||
$tabEl.width(originalWidth);
|
||||
$input.remove();
|
||||
me.onWindowResize();
|
||||
}
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$input.on('click', function(e) {
|
||||
e.stopPropagation()
|
||||
});
|
||||
},
|
||||
|
||||
renameWorksheet(sheetFromUpdate, fromUpdate) {
|
||||
const me = this;
|
||||
me.isRenameErrorShown = false;
|
||||
me.renamingWorksheet = this.api.asc_getActiveWorksheetId();
|
||||
const sindex = me.api.asc_getActiveWorksheetIndex();
|
||||
if (me.api.asc_isWorksheetLockedOrDeleted(sindex)) return;
|
||||
|
||||
const wc = me.api.asc_getWorksheetsCount();
|
||||
|
||||
var tab = sheetFromUpdate ? _.findWhere(me.statusbar.tabbar.tabs, { sheetid: sheetFromUpdate }) : me.statusbar.tabbar.tabs[sindex];
|
||||
var currentName = sheetFromUpdate ? me.renameInputVal : me.api.asc_getWorksheetName(sindex);
|
||||
if (!tab) return;
|
||||
const $tabEl = tab.$el.find('span');
|
||||
if ($tabEl.find('input.inline-rename').length > 0) return;
|
||||
|
||||
const otherNames = Array.from({ length: wc }, function(_, i) {
|
||||
return i !== sindex ? me.api.asc_getWorksheetName(i).toLowerCase() : null;
|
||||
}
|
||||
).filter(Boolean);
|
||||
|
||||
$tabEl.contents().filter(function(_, node) {
|
||||
return node.nodeType === 3;
|
||||
}).remove();
|
||||
|
||||
setTimeout(function() {
|
||||
const originalWidth = $tabEl.width();
|
||||
const $input = me.createRenameInput(currentName);
|
||||
|
||||
$tabEl.append($input);
|
||||
me.updateInputWidth($input, $tabEl);
|
||||
if (fromUpdate) {
|
||||
$input[0].focus();
|
||||
$input[0].setSelectionRange(me.renameInputCaret, me.renameInputCaret);
|
||||
} else {
|
||||
$input.focus().select();
|
||||
}
|
||||
if (!tab.isActive()) {
|
||||
me.api.asc_showWorksheet(tab.sheetindex);
|
||||
}
|
||||
me.bindRenameEvents($input, $tabEl, tab, currentName, otherNames, originalWidth);
|
||||
}, 10);
|
||||
},
|
||||
|
||||
moveWorksheet: function(selectArr, cut, silent, indTo) {
|
||||
@ -980,6 +1123,8 @@ define([
|
||||
strSheet : 'Sheet',
|
||||
textSheetViewTip: 'You are in Sheet View mode. Filters and sorting are visible only to you and those who are still in this view.',
|
||||
textSheetViewTipFilters: 'You are in Sheet View mode. Filters are visible only to you and those who are still in this view.',
|
||||
textDisconnect: '<b>Connection is lost</b><br>Trying to connect. Please check connection settings.'
|
||||
textDisconnect: '<b>Connection is lost</b><br>Trying to connect. Please check connection settings.',
|
||||
errSheetNameRules : "<b>You typed an invalid sheet name:</b><br>- A sheet name cannot be empty.<br>- A sheet name cannot contain the following characters: \ / * ? [ ] : or the character ' as first or last character.",
|
||||
errNameExists : 'Sheet with such a name already exists.'
|
||||
}, SSE.Controllers.Statusbar || {}));
|
||||
});
|
||||
@ -444,26 +444,28 @@ define([
|
||||
|
||||
update: function() {
|
||||
var me = this;
|
||||
|
||||
var renamingWorksheet = this.controller && this.controller.renamingWorksheet;
|
||||
this.tabbar.empty(true);
|
||||
this.tabMenu.items[5].menu.removeAll();
|
||||
this.tabMenu.items[5].hide();
|
||||
this.btnAddWorksheet.setDisabled(true);
|
||||
this.sheetListMenu.removeAll();
|
||||
|
||||
if (this.api) {
|
||||
var wc = this.api.asc_getWorksheetsCount(), i = -1;
|
||||
var hidentems = [], items = [], allItems = [], tab, locked, name;
|
||||
var sindex = this.api.asc_getActiveWorksheetIndex();
|
||||
var wbprotected = this.api.asc_isProtectedWorkbook();
|
||||
var sid = me.api.asc_getActiveWorksheetId();
|
||||
|
||||
while (++i < wc) {
|
||||
locked = me.api.asc_isWorksheetLockedOrDeleted(i);
|
||||
name = me.api.asc_getActiveNamedSheetView ? me.api.asc_getActiveNamedSheetView(i) || '' : '';
|
||||
var sheetid = me.api.asc_getWorksheetId(i)
|
||||
tab = {
|
||||
sheetindex : i,
|
||||
sheetid : sheetid,
|
||||
index : items.length,
|
||||
active : sindex == i,
|
||||
active : renamingWorksheet ? renamingWorksheet === sheetid : sid === sheetid,
|
||||
label : me.api.asc_getWorksheetName(i),
|
||||
// reorderable : !locked,
|
||||
cls : locked ? 'coauth-locked':'',
|
||||
@ -475,7 +477,6 @@ define([
|
||||
this.api.asc_isWorksheetHidden(i)? hidentems.push(tab) : items.push(tab);
|
||||
allItems.push(tab);
|
||||
}
|
||||
|
||||
if (hidentems.length) {
|
||||
hidentems.forEach(function(item){
|
||||
me.tabMenu.items[5].menu.addItem(new Common.UI.MenuItem({
|
||||
@ -489,12 +490,27 @@ define([
|
||||
|
||||
this.tabbar.add(items);
|
||||
|
||||
if (renamingWorksheet) {
|
||||
const tab = _.findWhere(this.tabbar.tabs, { sheetid: renamingWorksheet });
|
||||
if (tab) {
|
||||
setTimeout(() => {
|
||||
me.onSheetChanged(0, tab.sheetindex, tab);
|
||||
this.controller.renameWorksheet(renamingWorksheet, true);
|
||||
}, 50);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.tabbar.setActive(sindex)
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
|
||||
allItems.forEach(function(item){
|
||||
var hidden = me.api.asc_isWorksheetHidden(item.sheetindex);
|
||||
me.sheetListMenu.addItem(new Common.UI.MenuItem({
|
||||
style: 'white-space: pre',
|
||||
caption: Common.Utils.String.htmlEncode(item.label),
|
||||
value: item.sheetindex,
|
||||
sheetid: item.sheetid,
|
||||
checkable: true,
|
||||
checked: item.active,
|
||||
hidden: hidden,
|
||||
|
||||
@ -1613,6 +1613,8 @@
|
||||
"SSE.Controllers.Statusbar.textSheetViewTipFilters": "You are in Sheet View mode. Filters are visible only to you and those who are still in this view.",
|
||||
"SSE.Controllers.Statusbar.warnDeleteSheet": "The selected sheets might contain data. Are you sure you want to proceed?",
|
||||
"SSE.Controllers.Statusbar.zoomText": "Zoom {0}%",
|
||||
"SSE.Controllers.Statusbar.errNameExists": "Sheet with such a name already exists.",
|
||||
"SSE.Controllers.Statusbar.errSheetNameRules": "<b>You typed an invalid sheet name:</b><br>- A sheet name cannot be empty.<br>- A sheet name cannot contain the following characters: \\ / * ? [ ] : or the character ' as first or last character.",
|
||||
"SSE.Controllers.Toolbar.confirmAddFontName": "The font you are going to save is not available on the current device.<br>The text style will be displayed using one of the system fonts, the saved font will be used when it is available.<br>Do you want to continue?",
|
||||
"SSE.Controllers.Toolbar.errorComboSeries": "To create a combination chart, select at least two series of data.",
|
||||
"SSE.Controllers.Toolbar.errorMaxPoints": "The maximum number of points in series per chart is 4096.",
|
||||
|
||||
Reference in New Issue
Block a user