559 lines
22 KiB
JavaScript
559 lines
22 KiB
JavaScript
import React, {Fragment} from 'react';
|
|
import {Link} from 'framework7-react';
|
|
import { Device } from '../../web-apps/apps/common/mobile/utils/device';
|
|
|
|
const EditorUIController = () => {
|
|
return null
|
|
};
|
|
|
|
EditorUIController.isSupportEditFeature = () => {
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
|
|
This is the file where the magic happens.
|
|
Try to figure out a working version from a both the old commits
|
|
and my hunches from hacking around in the old webapp editor
|
|
|
|
https://github.com/ONLYOFFICE/web-apps/commit/7c72e8cb1b3e06ac72b0e7156d33b8a8d3206dc4
|
|
*/
|
|
|
|
EditorUIController.toolbarOptions = {
|
|
// This implementation is likely incomplete, since wsProps, focusOn, isShapeLocked are currently ununsed
|
|
// and wsProps was specifically added to the options given to getEditOptions in order to handle protection
|
|
// https://github.com/ONLYOFFICE/web-apps/commit/1508b2ee641e9f8e633628dfe7e76bfe8a2f82b2#diff-9358b4112e282a95c6f9568c509cfa89d866b92701dfd5d347349ad85971e53eR31
|
|
// wsProps contains severals properties that are true if specific protection is enabled
|
|
getEditOptions: (options) => {
|
|
// console.log('EditorUIController.toolbarOptions.getEditOptions' ,options);
|
|
return (
|
|
<Fragment>
|
|
<Link className={options.disabled && 'disabled'} id='btn-edit' icon='icon-edit-settings' href={false} onClick={() => options.onEditClick()}></Link>
|
|
<Link className={options.disabled && 'disabled'} id='btn-add' icon='icon-plus' href={false} onClick={() => options.onAddClick()}></Link>
|
|
</Fragment>
|
|
);
|
|
},
|
|
|
|
getUndoRedo: (options) => {
|
|
return (
|
|
<Fragment>
|
|
<Link icon='icon-undo' className={options.disabledUndo && 'disabled'} onClick={() => options.onUndoClick()}></Link>
|
|
<Link icon='icon-redo' className={options.disabledRedo && 'disabled'} onClick={() => options.onRedoClick()}></Link>
|
|
</Fragment>
|
|
);
|
|
}
|
|
}
|
|
|
|
EditorUIController.initCellInfo = (props) => {
|
|
// console.log('EditorUIController.initCellInfo', props);
|
|
|
|
const storeFocusObjects = props.storeFocusObjects;
|
|
const storeCellSettings = props.storeCellSettings;
|
|
const storeTextSettings = props.storeTextSettings;
|
|
const storeChartSettings = props.storeChartSettings;
|
|
const api = Common.EditorApi.get();
|
|
|
|
storeFocusObjects.intf = EditorUIController.Intf(storeFocusObjects);
|
|
|
|
api.asc_registerCallback('asc_onSelectionChanged', cellInfo => {
|
|
// console.log("asc_onSelectionChanged",cellInfo);
|
|
// console.log('storeFocusObjects', {
|
|
// 'isLocked': storeFocusObjects.isLocked,
|
|
// 'isLockedText': storeFocusObjects.isLockedText,
|
|
// 'isLockedShaped': storeFocusObjects.isLockedShaped,
|
|
// 'editFormulaMode': storeFocusObjects.editFormulaMode,
|
|
// 'isEditCell': storeFocusObjects.isEditCell,
|
|
// 'functionDisabled': storeFocusObjects.functionDisabled
|
|
// });
|
|
|
|
// TODO Not sure if good idea or not but maybe we should check if cell is locked
|
|
// In that case, get the protected ranges and see if we should allow to select
|
|
// that cell.
|
|
// const api = Common.EditorApi.get();
|
|
|
|
// console.log({
|
|
// 'api.asc_isProtectedSheet': api.asc_isProtectedSheet(),
|
|
// 'api.asc_checkLockedCells': api.asc_checkLockedCells(),
|
|
// 'shouldCheckProtectedRanges': api.asc_isProtectedSheet() && api.asc_checkLockedCells(),
|
|
// 'iscelllocked': api.asc_isProtectedSheet() && api.asc_checkLockedCells() ? api.asc_checkProtectedRange() : false
|
|
// });
|
|
|
|
// This changes the type of the selected focus to show different edit views.
|
|
// The edit views needs the focusOn value to be set.
|
|
// Since this change was made after the mobile editor has been made private, I'm not
|
|
// sure if this is the way to know if the selection is a cell or an object but this
|
|
// seems to work. this old commit shows how changeFocus used to work:
|
|
// https://github.com/ONLYOFFICE/web-apps/commit/050c03096243448b040fc676cd350c090a1a8c59
|
|
const isObject = cellInfo.asc_getSelectionType() !== Asc.c_oAscSelectionType.RangeCells;
|
|
storeFocusObjects.changeFocus(isObject);
|
|
|
|
storeFocusObjects.resetCellInfo(cellInfo);
|
|
storeCellSettings.initCellSettings(cellInfo);
|
|
storeTextSettings.initTextSettings(cellInfo);
|
|
|
|
let selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps();
|
|
|
|
if(selectedObjects.length) {
|
|
storeFocusObjects.resetFocusObjects(selectedObjects);
|
|
|
|
// Chart Settings
|
|
|
|
if (storeFocusObjects.chartObject) {
|
|
storeChartSettings.updateChartStyles(api.asc_getChartPreviews(storeFocusObjects.chartObject.get_ChartProperties().getType()));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
EditorUIController.initFonts = (props) => {
|
|
// console.log('EditorUIController.initFonts', storeTextSettings);
|
|
|
|
const storeCellSettings = props.storeCellSettings;
|
|
const storeTextSettings = props.storeTextSettings;
|
|
const api = Common.EditorApi.get();
|
|
api.asc_registerCallback('asc_onInitEditorFonts', (fonts, select) => {
|
|
// console.log('asc_onInitEditorFonts', fonts, select);
|
|
storeCellSettings.initEditorFonts(fonts, select);
|
|
storeTextSettings.initEditorFonts(fonts, select);
|
|
});
|
|
|
|
// Maybe this go here ?
|
|
api.asc_registerCallback('asc_onEditorSelectionChanged', fontObj => {
|
|
// console.log(fontObj)
|
|
storeCellSettings.initFontInfo(fontObj);
|
|
storeTextSettings.initFontInfo(fontObj);
|
|
});
|
|
};
|
|
EditorUIController.initEditorStyles = (storeCellSettings) => {
|
|
// console.log('EditorUIController.initEditorStyles', storeCellSettings);
|
|
|
|
const api = Common.EditorApi.get();
|
|
api.asc_registerCallback('asc_onInitEditorStyles', styles => {
|
|
storeCellSettings.initCellStyles(styles);
|
|
});
|
|
}
|
|
|
|
EditorUIController.initThemeColors = () => {
|
|
// console.log('EditorUIController.initThemeColors');
|
|
const api = Common.EditorApi.get();
|
|
api.asc_registerCallback('asc_onSendThemeColors', (colors, standart_colors) => {
|
|
// console.log('asc_onSendThemeColors', colors, standart_colors);
|
|
Common.Utils.ThemeColor.setColors(colors, standart_colors);
|
|
});
|
|
}
|
|
|
|
EditorUIController.ContextMenu = {
|
|
// https://github.com/ONLYOFFICE/web-apps/commit/588a7f03863ebf9ec3251a36decc8b4e280dda59
|
|
mapMenuItems: (contextMenu) => {
|
|
// console.log('EditorUIController.ContextMenu.mapMenuItems', contextMenu);
|
|
|
|
if ( !Common.EditorApi ) return [];
|
|
|
|
const { t } = contextMenu.props;
|
|
const _t = t("ContextMenu", { returnObjects: true });
|
|
|
|
const { canViewComments } = contextMenu.props;
|
|
|
|
const api = Common.EditorApi.get();
|
|
const cellinfo = api.asc_getCellInfo();
|
|
|
|
const itemsIcon = [];
|
|
const itemsText = [];
|
|
|
|
let iscellmenu, isrowmenu, iscolmenu, isallmenu, ischartmenu, isimagemenu, istextshapemenu, isshapemenu, istextchartmenu;
|
|
let iscelllocked = cellinfo.asc_getLocked();
|
|
const seltype = cellinfo.asc_getSelectionType();
|
|
const xfs = cellinfo.asc_getXfs();
|
|
const isComments = cellinfo.asc_getComments().length > 0; //prohibit adding multiple comments in one cell;
|
|
|
|
// Check if the individual cell is locked
|
|
// This code is taken from ./web-apps/apps/spreadsheeteditor/main/app/controller/Main.js
|
|
// It seems that api.asc_checkProtectedRange() returns null if the cell is locked.
|
|
iscelllocked = api.asc_isProtectedSheet() && api.asc_checkLockedCells() ? api.asc_checkProtectedRange() : false;
|
|
iscelllocked = iscelllocked === null ? true : false;
|
|
|
|
const { isDisconnected } = contextMenu.props;
|
|
|
|
switch (seltype) {
|
|
case Asc.c_oAscSelectionType.RangeCells: iscellmenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeRow: isrowmenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeCol: iscolmenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeMax: isallmenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeImage: isimagemenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeShape: isshapemenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeChart: ischartmenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeChartText: istextchartmenu = true; break;
|
|
case Asc.c_oAscSelectionType.RangeShapeText: istextshapemenu = true; break;
|
|
}
|
|
|
|
if (!iscelllocked && (isimagemenu || isshapemenu || ischartmenu || istextshapemenu || istextchartmenu)) {
|
|
api.asc_getGraphicObjectProps().every((object) => {
|
|
if (object.asc_getObjectType() == Asc.c_oAscTypeSelectElement.Image) {
|
|
iscelllocked = object.asc_getObjectValue().asc_getLocked();
|
|
}
|
|
return !iscelllocked;
|
|
});
|
|
}
|
|
|
|
if (iscelllocked || api.isCellEdited) {
|
|
itemsIcon.push({
|
|
event: 'copy',
|
|
icon: 'icon-copy'
|
|
});
|
|
|
|
} else {
|
|
itemsIcon.push({
|
|
event: 'cut',
|
|
icon: 'icon-cut'
|
|
});
|
|
itemsIcon.push({
|
|
event: 'copy',
|
|
icon: 'icon-copy'
|
|
});
|
|
itemsIcon.push({
|
|
event: 'paste',
|
|
icon: 'icon-paste'
|
|
});
|
|
itemsText.push({
|
|
caption: _t.menuDelete,
|
|
event: 'del'
|
|
});
|
|
|
|
if (isimagemenu || isshapemenu || ischartmenu ||
|
|
istextshapemenu || istextchartmenu) {
|
|
itemsText.push({
|
|
caption: _t.menuEdit,
|
|
event: 'edit'
|
|
});
|
|
} else {
|
|
if (iscolmenu || isrowmenu) {
|
|
itemsText.push({
|
|
caption: _t.menuHide,
|
|
event: 'hide'
|
|
});
|
|
itemsText.push({
|
|
caption: _t.menuShow,
|
|
event: 'show'
|
|
});
|
|
} else if (iscellmenu) {
|
|
if (!iscelllocked) {
|
|
itemsText.push({
|
|
caption: _t.menuCell,
|
|
event: 'edit'
|
|
});
|
|
}
|
|
|
|
if (cellinfo.asc_getMerge() == Asc.c_oAscMergeOptions.None) {
|
|
itemsText.push({
|
|
caption: _t.menuMerge,
|
|
event: 'merge'
|
|
});
|
|
}
|
|
|
|
if (cellinfo.asc_getMerge() == Asc.c_oAscMergeOptions.Merge) {
|
|
itemsText.push({
|
|
caption: _t.menuUnmerge,
|
|
event: 'unmerge'
|
|
});
|
|
}
|
|
|
|
itemsText.push(
|
|
xfs.asc_getWrapText() ?
|
|
{
|
|
caption: _t.menuUnwrap,
|
|
event: 'unwrap'
|
|
} :
|
|
{
|
|
caption: _t.menuWrap,
|
|
event: 'wrap'
|
|
});
|
|
|
|
if (cellinfo.asc_getHyperlink() && !cellinfo.asc_getMultiselect()) {
|
|
itemsText.push({
|
|
caption: _t.menuOpenLink,
|
|
event: 'openlink'
|
|
});
|
|
itemsText.push({
|
|
caption: _t.menuEditLink,
|
|
event: 'editlink'
|
|
});
|
|
} else if (!cellinfo.asc_getHyperlink() && !cellinfo.asc_getMultiselect() &&
|
|
!cellinfo.asc_getLockText() && !!cellinfo.asc_getText()) {
|
|
itemsText.push({
|
|
caption: _t.menuAddLink,
|
|
event: 'addlink'
|
|
});
|
|
}
|
|
}
|
|
|
|
itemsText.push({
|
|
caption: api.asc_getSheetViewSettings().asc_getIsFreezePane() ? _t.menuUnfreezePanes : _t.menuFreezePanes,
|
|
event: 'freezePanes'
|
|
});
|
|
|
|
}
|
|
|
|
if (canViewComments) {
|
|
if (isComments) {
|
|
itemsText.push({
|
|
caption: _t.menuViewComment,
|
|
event: 'viewcomment'
|
|
});
|
|
} else if (iscellmenu) {
|
|
itemsText.push({
|
|
caption: _t.menuAddComment,
|
|
event: 'addcomment'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// The below is guesswork on how Onlyoffice should handle itself with locked cells.
|
|
if(iscelllocked) {
|
|
if (iscellmenu && cellinfo.asc_getHyperlink()) {
|
|
itemsText.push({
|
|
caption: _t.menuOpenLink,
|
|
event: 'openlink'
|
|
});
|
|
}
|
|
|
|
const {isRestrictedEdit, canViewComments, canCoAuthoring, canComments, isResolvedComments, isVersionHistoryMode} = contextMenu.props;
|
|
const comments = cellinfo.asc_getComments(); //prohibit adding multiple comments in one cell;
|
|
|
|
if(!isDisconnected && !isVersionHistoryMode) {
|
|
if (canViewComments && comments && comments.length && ((!isSolvedComment && !isResolvedComments) || isResolvedComments)) {
|
|
itemsText.push({
|
|
caption: _t.menuViewComment,
|
|
event: 'viewcomment'
|
|
});
|
|
}
|
|
|
|
if (iscellmenu && !api.isCellEdited && isRestrictedEdit && canCoAuthoring && canComments && comments && comments.length<1) {
|
|
itemsText.push({
|
|
caption: _t.menuAddComment,
|
|
event: 'addcomment'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Device.phone && itemsText.length > 2 ) {
|
|
contextMenu.extraItems = itemsText.splice(2,itemsText.length, {
|
|
caption: _t.menuMore,
|
|
event: 'showActionSheet'
|
|
});
|
|
}
|
|
|
|
return itemsIcon.concat(itemsText);
|
|
} ,
|
|
// https://github.com/ONLYOFFICE/web-apps/commit/588a7f03863ebf9ec3251a36decc8b4e280dda59
|
|
handleMenuItemClick: (contextMenu, action) => {
|
|
// console.log('EditorUIController.ContextMenu.handleMenuItemClick', contextMenu, action);
|
|
|
|
const api = Common.EditorApi.get();
|
|
const info = api.asc_getCellInfo();
|
|
switch (action) {
|
|
case 'addcomment':
|
|
Common.Notifications.trigger('addcomment');
|
|
return true;
|
|
case 'del':
|
|
api.asc_emptyCells(Asc.c_oAscCleanOptions.All);
|
|
return true;
|
|
case 'wrap':
|
|
api.asc_setCellTextWrap(true);
|
|
return true;
|
|
case 'unwrap':
|
|
api.asc_setCellTextWrap(false);
|
|
return true;
|
|
case 'edit':
|
|
setTimeout(() => {
|
|
contextMenu.props.openOptions('edit');
|
|
}, 0);
|
|
return true;
|
|
case 'merge':
|
|
if (api.asc_mergeCellsDataLost(Asc.c_oAscMergeOptions.Merge)) {
|
|
setTimeout(() => {
|
|
f7.dialog.confirm(_t.warnMergeLostData, _t.notcriticalErrorTitle, () => {
|
|
api.asc_mergeCells(Asc.c_oAscMergeOptions.Merge);
|
|
});
|
|
}, 0);
|
|
} else {
|
|
api.asc_mergeCells(Asc.c_oAscMergeOptions.Merge);
|
|
}
|
|
return true;
|
|
case 'unmerge':
|
|
api.asc_mergeCells(Asc.c_oAscMergeOptions.None);
|
|
return true;
|
|
case 'hide':
|
|
api[info.asc_getSelectionType() == Asc.c_oAscSelectionType.RangeRow ? 'asc_hideRows' : 'asc_hideColumns']();
|
|
return true;
|
|
case 'show':
|
|
api[info.asc_getSelectionType() == Asc.c_oAscSelectionType.RangeRow ? 'asc_showRows' : 'asc_showColumns']();
|
|
return true;
|
|
case 'addlink':
|
|
setTimeout(() => {
|
|
contextMenu.props.openOptions('add', 'link');
|
|
}, 400)
|
|
return true;
|
|
case 'editlink':
|
|
setTimeout(() => {
|
|
contextMenu.props.openOptions('edit', 'link');
|
|
}, 400)
|
|
return true;
|
|
case 'freezePanes':
|
|
api.asc_freezePane();
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
};
|
|
|
|
// This objects holds the mysterious functions in focusObjects.js inside the intf object
|
|
// These for now are based on the latest valid implementation from the mobile editor
|
|
// https://github.com/ONLYOFFICE/web-apps/commit/7c72e8cb1b3e06ac72b0e7156d33b8a8d3206dc4#diff-a9931472dbd29941dda676251382f80122ff2f08aadc849684e08b505d174bf2
|
|
EditorUIController.Intf = function (storeFocusObjects) {
|
|
var obj = {};
|
|
|
|
obj.getSelections = () => {
|
|
const _selections = [];
|
|
|
|
let isCell, isRow, isCol, isAll, isChart, isImage, isTextShape, isShape, isTextChart,
|
|
selType = storeFocusObjects._cellInfo.asc_getSelectionType(),
|
|
isObjLocked = false;
|
|
|
|
switch (selType) {
|
|
case Asc.c_oAscSelectionType.RangeCells: isCell = true; break;
|
|
case Asc.c_oAscSelectionType.RangeRow: isRow = true; break;
|
|
case Asc.c_oAscSelectionType.RangeCol: isCol = true; break;
|
|
case Asc.c_oAscSelectionType.RangeMax: isAll = true; break;
|
|
case Asc.c_oAscSelectionType.RangeImage: isImage = true; break;
|
|
case Asc.c_oAscSelectionType.RangeShape: isShape = true; break;
|
|
case Asc.c_oAscSelectionType.RangeChart: isChart = true; break;
|
|
case Asc.c_oAscSelectionType.RangeChartText:isTextChart = true; break;
|
|
case Asc.c_oAscSelectionType.RangeShapeText: isTextShape = true; break;
|
|
}
|
|
|
|
if (isImage || isShape || isChart) {
|
|
isImage = isShape = isChart = false;
|
|
let has_chartprops = false;
|
|
let selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps();
|
|
|
|
for (let i = 0; i < selectedObjects.length; i++) {
|
|
if (selectedObjects[i].asc_getObjectType() == Asc.c_oAscTypeSelectElement.Image) {
|
|
const elValue = selectedObjects[i].asc_getObjectValue();
|
|
isObjLocked = isObjLocked || elValue.asc_getLocked();
|
|
const shapeProps = elValue.asc_getShapeProperties();
|
|
|
|
if (shapeProps) {
|
|
if (shapeProps.asc_getFromChart()) {
|
|
isChart = true;
|
|
} else {
|
|
isShape = true;
|
|
|
|
}
|
|
} else if (elValue.asc_getChartProperties()) {
|
|
isChart = true;
|
|
has_chartprops = true;
|
|
} else {
|
|
isImage = true;
|
|
}
|
|
}
|
|
}
|
|
} else if (isTextShape || isTextChart) {
|
|
const selectedObjects = Common.EditorApi.get().asc_getGraphicObjectProps();
|
|
let isEquation = false;
|
|
|
|
for (var i = 0; i < selectedObjects.length; i++) {
|
|
const elType = selectedObjects[i].asc_getObjectType();
|
|
if (elType == Asc.c_oAscTypeSelectElement.Image) {
|
|
const value = selectedObjects[i].asc_getObjectValue();
|
|
isObjLocked = isObjLocked || value.asc_getLocked();
|
|
} else if (elType == Asc.c_oAscTypeSelectElement.Paragraph) {
|
|
} else if (elType == Asc.c_oAscTypeSelectElement.Math) {
|
|
isEquation = true;
|
|
}
|
|
}
|
|
}
|
|
if (isChart || isTextChart) {
|
|
_selections.push('chart');
|
|
|
|
if (isTextChart) {
|
|
_selections.push('text');
|
|
}
|
|
} else if ((isShape || isTextShape) && !isImage) {
|
|
_selections.push('shape');
|
|
|
|
if (isTextShape) {
|
|
_selections.push('text');
|
|
}
|
|
} else if (isImage) {
|
|
_selections.push('image');
|
|
|
|
if (isShape) {
|
|
_selections.push('shape');
|
|
}
|
|
} else {
|
|
_selections.push('cell');
|
|
|
|
if (storeFocusObjects._cellInfo.asc_getHyperlink()) {
|
|
_selections.push('hyperlink');
|
|
}
|
|
}
|
|
return _selections;
|
|
}
|
|
|
|
obj.getShapeObject = () => {
|
|
const shapes = [];
|
|
for (let object of storeFocusObjects._focusObjects) {
|
|
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
|
|
if (object.get_ObjectValue() && object.get_ObjectValue().get_ShapeProperties()) {
|
|
shapes.push(object);
|
|
}
|
|
}
|
|
}
|
|
if (shapes.length > 0) {
|
|
const object = shapes[shapes.length - 1]; // get top
|
|
return object.get_ObjectValue();
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
obj.getImageObject = () => {
|
|
const images = [];
|
|
for (let object of storeFocusObjects._focusObjects) {
|
|
if (object.get_ObjectType() == Asc.c_oAscTypeSelectElement.Image) {
|
|
images.push(object);
|
|
}
|
|
}
|
|
if (images.length > 0) {
|
|
const object = images[images.length - 1]; // get top
|
|
return object.get_ObjectValue();
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
obj.getChartObject = () => {
|
|
const charts = [];
|
|
for (let object of storeFocusObjects._focusObjects) {
|
|
if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Image) {
|
|
if (object.get_ObjectValue() && object.get_ObjectValue().get_ChartProperties()) {
|
|
charts.push(object);
|
|
}
|
|
}
|
|
}
|
|
if (charts.length > 0) {
|
|
const object = charts[charts.length - 1]; // get top table
|
|
return object.get_ObjectValue();
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
export default EditorUIController;
|