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 ( options.onEditClick()}> options.onAddClick()}> ); }, getUndoRedo: (options) => { return ( options.onUndoClick()}> options.onRedoClick()}> ); } } 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;