/* * This file is part of ORY Editor. * * ORY Editor is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ORY Editor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with ORY Editor. If not, see . * * @license LGPL-3.0 * @copyright 2016-2018 Aeneas Rekkas * @author Aeneas Rekkas * */ import flatten from 'ramda/src/flatten'; import head from 'ramda/src/head'; import path from 'ramda/src/path'; import pathOr from 'ramda/src/pathOr'; import map from 'ramda/src/map'; import reduce from 'ramda/src/reduce'; import tail from 'ramda/src/tail'; import takeWhile from 'ramda/src/takeWhile'; import { SET_DISPLAY_MODE, SetDisplayModeAction } from '../../../actions/display'; import { Row } from '../../../types/editable'; const notSharp = (c: string) => c !== '#'; export const mergeRows = (state: Row[]) => { if (state.length < 2) { return state; } const [newCellsAcc, lastRow] = reduce( ([rowsAcc, rowA]: [Row[], Row], rowB: Row) => { const numberOfCells = path(['cells', 'length']); if (numberOfCells(rowA) !== 1 || numberOfCells(rowB) !== 1) { return [ [...rowsAcc, { ...rowA, id: takeWhile(notSharp, rowA.id).join('') }], rowB, ]; } const cellA = rowA.cells[0]; const cellB = rowB.cells[0]; const pluginName = path(['content', 'plugin', 'name']); const pluginVersion = path(['content', 'plugin', 'version']); const pluginMerge = path(['content', 'plugin', 'merge']); if ( !pluginName(cellA) || !pluginName(cellB) || !pluginVersion(cellA) || !pluginVersion(cellB) || pluginName(cellA) !== pluginName(cellB) || pluginVersion(cellA) !== pluginVersion(cellB) || !pluginMerge(cellA) ) { return [ [...rowsAcc, { ...rowA, id: takeWhile(notSharp, rowA.id).join('') }], rowB, ]; } return [ rowsAcc, { ...rowA, id: takeWhile(notSharp, rowA.id).join(''), cells: [ { ...cellA, id: takeWhile(notSharp, cellA.id).join(''), content: { ...cellA.content, state: pluginMerge(cellA)([ pathOr({}, ['content', 'state'], cellA), pathOr({}, ['content', 'state'], cellB), ]), }, }, ], }, ]; }, [[], head(state)], tail(state) ); return [...newCellsAcc, lastRow]; }; export const splitRows = (state: Row[]) => flatten( map((row: Row) => { if (!row.cells) { return [row]; } if (row.cells.length !== 1) { return [row]; } // tslint:disable-next-line:no-shadowed-variable const state = path(['cells', 0, 'content', 'state'], row); const split = path(['cells', 0, 'content', 'plugin', 'split'], row); if (!split) { return [row]; } // tslint:disable-next-line:no-shadowed-variable return split(state).map((state: Object, i: number) => ({ ...row, id: `${row.id}#${i}`, cells: [ { ...row.cells[0], id: `${row.cells[0].id}#${i}`, content: { ...row.cells[0].content, state, }, }, ], })); }, state) ); export const mergeDecorator = (action: SetDisplayModeAction) => ( state: Row[] ) => { if (action.type !== SET_DISPLAY_MODE) { return state; } switch (action.mode) { case 'edit': return mergeRows(state); case 'insert': case 'layout': { return splitRows(state); } default: return state; } };