From 1239b0192cbc746d82afff3c70cd3d123779fd86 Mon Sep 17 00:00:00 2001 From: Evgeny Kochetkov Date: Fri, 29 Jun 2018 12:45:12 +0300 Subject: [PATCH] fix(xod-client): make computation of bounding boxes safer Fixes #1312 --- packages/xod-client/src/editor/utils.js | 2 + packages/xod-client/src/project/nodeLayout.js | 37 +++++++++++-------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/packages/xod-client/src/editor/utils.js b/packages/xod-client/src/editor/utils.js index b4d01e17..ec202164 100644 --- a/packages/xod-client/src/editor/utils.js +++ b/packages/xod-client/src/editor/utils.js @@ -92,6 +92,7 @@ export const getNewSelection = R.compose( // :: ClipboardEntities -> Position export const getBBoxTopLeftPosition = R.compose( + foldMaybe({ x: 0, y: 0 }, R.identity), getTopLeftPosition, R.converge(R.concat, [ R.compose(R.map(XP.getNodePosition), R.prop('nodes')), @@ -124,6 +125,7 @@ const getCommentBottomRightPosition = R.converge(addPoints, [ export const getBBoxBottomRightPosition = R.curry( (currentPatch, project, entities) => R.compose( + foldMaybe({ x: 0, y: 0 }, R.identity), getBottomRightPosition, R.converge(R.concat, [ R.compose( diff --git a/packages/xod-client/src/project/nodeLayout.js b/packages/xod-client/src/project/nodeLayout.js index 45c5e0de..9ac2f75a 100644 --- a/packages/xod-client/src/project/nodeLayout.js +++ b/packages/xod-client/src/project/nodeLayout.js @@ -1,4 +1,6 @@ import * as R from 'ramda'; +import { Maybe } from 'ramda-fantasy'; +import { foldMaybe } from 'xod-func-tools'; const BASE_SIZE_UNIT = 17; @@ -160,21 +162,28 @@ export const snapNodeSizeToSlots = R.compose( sizeToPoint ); -// :: ([Number] -> Number) -> ([Number] -> Number) -> [Position] -> Position +// :: ([Number] -> Number) -> ([Number] -> Number) -> [Position] -> Maybe Position export const findPosition = R.uncurryN(3)((xFn, yFn) => - R.converge((x, y) => ({ x, y }), [ - R.compose(xFn, R.map(R.prop('x'))), - R.compose(yFn, R.map(R.prop('y'))), - ]) + R.ifElse( + R.isEmpty, + R.always(Maybe.Nothing()), + R.compose( + Maybe.Just, + R.converge((x, y) => ({ x, y }), [ + R.compose(xFn, R.map(R.prop('x'))), + R.compose(yFn, R.map(R.prop('y'))), + ]) + ) + ) ); -// :: [Position] -> Position +// :: [Position] -> Maybe Position export const getTopLeftPosition = findPosition( R.apply(Math.min), R.apply(Math.min) ); -// :: [Position] -> Position +// :: [Position] -> Maybe Position export const getBottomRightPosition = findPosition( R.apply(Math.max), R.apply(Math.max) @@ -182,12 +191,10 @@ export const getBottomRightPosition = findPosition( // Given a list of positions of all entities, returns optimal patch panning offset // :: [Position] -> Position -export const getOptimalPanningOffset = R.ifElse( - R.isEmpty, - R.always(DEFAULT_PANNING_OFFSET), - R.compose( - addPoints(DEFAULT_PANNING_OFFSET), - R.map(R.negate), - getTopLeftPosition - ) +export const getOptimalPanningOffset = R.compose( + foldMaybe( + DEFAULT_PANNING_OFFSET, + R.pipe(R.map(R.negate), addPoints(DEFAULT_PANNING_OFFSET)) + ), + getTopLeftPosition );