Skip to content
This repository has been archived by the owner on Oct 25, 2022. It is now read-only.

Commit

Permalink
Moved all utilities of StyleMenu into StyleMenu directory
Browse files Browse the repository at this point in the history
  • Loading branch information
silviubogan committed Oct 8, 2020
1 parent ebd919f commit cbb0779
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 275 deletions.
27 changes: 17 additions & 10 deletions src/editor/plugins/StyleMenu/StyleMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import React from 'react';
import { useSlate } from 'slate-react';
import { Editor } from 'slate';
import Select, { components } from 'react-select';
import Select from 'react-select';
import { useIntl, defineMessages } from 'react-intl';
import { settings } from '~/config';
import {
isBlockStyleActive,
isInlineStyleActive,
toggleStyle,
} from '../../../utils/blocks';
import { isBlockStyleActive, isInlineStyleActive, toggleStyle } from './utils';

const messages = defineMessages({
allStylesApplied: {
id: 'All Styles Applied',
defaultMessage: 'All Styles Applied',
},
noStyle: {
id: 'No Style',
defaultMessage: 'No Style',
},
fontStyle: {
id: 'Font Style',
defaultMessage: 'Font Style',
},
paragraphStyle: {
id: 'Paragraph Style',
defaultMessage: 'Paragraph Style',
},
});

const brownColor = '#826A6A';
Expand Down Expand Up @@ -133,11 +140,11 @@ const StylingsButton = (props) => {
// TODO: i18n for the two strings used below
const opts = [
{
label: 'Paragraph Style',
label: intl.formatMessage(messages.paragraphStyle),
options: rawOpts.filter((x) => x.isBlock),
},
{
label: 'Font Style',
label: intl.formatMessage(messages.fontStyle),
options: rawOpts.filter((x) => !x.isBlock),
},
];
Expand Down Expand Up @@ -165,7 +172,7 @@ const StylingsButton = (props) => {
value={toSelect}
isMulti={true}
styles={selectStyles}
placeholder="No Style"
placeholder={intl.formatMessage(messages.noStyle)}
hideSelectedOptions={false}
noOptionsMessage={({ inputValue }) =>
intl.formatMessage(messages.allStylesApplied)
Expand Down
267 changes: 267 additions & 0 deletions src/editor/plugins/StyleMenu/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
import { settings } from '~/config';
import { Editor, Transforms } from 'slate';
import { isBlockActive, deconstructToVoltoBlocks } from 'volto-slate/utils';

/**
* Toggles a style (e.g. in the StyleMenu plugin).
* @param {Editor} editor
* @param {object} options
* @param {boolean} options.isRequested Whether the given style is requested by
* the user. The style is only applied if it is requested and only removed if it
* is not requested.
*/
export const toggleStyle = (editor, { cssClass, isBlock, isRequested }) => {
const isActive =
isBlockStyleActive(editor, cssClass) ||
isInlineStyleActive(editor, cssClass);

if (isRequested && isActive) {
// nothing to do
} else if (isRequested && !isActive) {
if (isBlock && !isBlockStyleActive(editor, cssClass)) {
toggleBlockStyle(editor, cssClass);
} else if (!isBlock && !isInlineStyleActive(editor, cssClass)) {
toggleInlineStyle(editor, cssClass);
}
} else if (!isRequested && isActive) {
if (isBlock && isBlockStyleActive(editor, cssClass)) {
toggleBlockStyle(editor, cssClass);
} else if (!isBlock && isInlineStyleActive(editor, cssClass)) {
toggleInlineStyle(editor, cssClass);
}
} else if (!isRequested && !isActive) {
// nothing to do
}
};

export const toggleBlockStyle = (editor, style) => {
// We have 6 boolean variables which need to be accounted for.
// See https://docs.google.com/spreadsheets/d/1mVeMuqSTMABV2BhoHPrPAFjn7zUksbNgZ9AQK_dcd3U/edit?usp=sharing
const { slate } = settings;

const isListItem = isBlockActive(editor, slate.listItemType);
const isActive = isBlockStyleActive(editor, style);
const wantsList = false;

if (isListItem && !wantsList) {
toggleBlockStyleAsListItem(editor, style);
} else if (isListItem && wantsList && !isActive) {
// switchListType(editor, format); // this will deconstruct to Volto blocks
} else if (!isListItem && wantsList) {
// changeBlockToList(editor, format);
} else if (!isListItem && !wantsList) {
internalToggleBlockStyle(editor, style);
} else {
console.warn('toggleBlockStyle case not covered, please examine:', {
wantsList,
isActive,
isListItem,
});
}
};

export const toggleInlineStyle = (editor, style) => {
// We have 6 boolean variables which need to be accounted for.
// See https://docs.google.com/spreadsheets/d/1mVeMuqSTMABV2BhoHPrPAFjn7zUksbNgZ9AQK_dcd3U/edit?usp=sharing
const { slate } = settings;

const isListItem = isBlockActive(editor, slate.listItemType);
const isActive = isInlineStyleActive(editor, style);
const wantsList = false;

if (isListItem && !wantsList) {
toggleInlineStyleAsListItem(editor, style);
} else if (isListItem && wantsList && !isActive) {
// switchListType(editor, format); // this will deconstruct to Volto blocks
} else if (!isListItem && wantsList) {
// changeBlockToList(editor, format);
} else if (!isListItem && !wantsList) {
internalToggleInlineStyle(editor, style);
} else {
console.warn('toggleInlineStyle case not covered, please examine:', {
wantsList,
isActive,
isListItem,
});
}
};

export const isBlockStyleActive = (editor, style) => {
const sn = Array.from(
Editor.nodes(editor, {
match: (n) => !Editor.isEditor(n) && typeof n.styleName === 'string',
mode: 'highest',
}),
);

for (const [n] of sn) {
if (n.styleName.split(' ').filter((x) => x === style).length > 0) {
return true;
}
}

return false;
};

export const isInlineStyleActive = (editor, style) => {
const m = Editor.marks(editor);
const keyName = `style-${style}`;
if (m && m[keyName]) {
return true;
}
return false;
};

export const internalToggleBlockStyle = (editor, style) => {
toggleBlockStyleInSelection(editor, style);
};

export const internalToggleInlineStyle = (editor, style) => {
toggleInlineStyleInSelection(editor, style);
};

/*
* Applies a block format unto a list item. Will split the list and deconstruct the
* block
*/
export const toggleFormatAsListItem = (editor, format) => {
const { slate } = settings;
Transforms.unwrapNodes(editor, {
match: (n) => slate.listTypes.includes(n.type),
split: true,
});

Transforms.setNodes(editor, {
type: format,
});

deconstructToVoltoBlocks(editor);
};

/*
* Applies a block format unto a list item. Will split the list and deconstruct the
* block
*/
export const toggleBlockStyleAsListItem = (editor, style) => {
const { slate } = settings;
Transforms.unwrapNodes(editor, {
match: (n) => slate.listTypes.includes(n.type),
split: true,
});

toggleBlockStyleInSelection(editor, style);

deconstructToVoltoBlocks(editor);
};

/*
* Applies an inline style unto a list item.
*/
export const toggleInlineStyleAsListItem = (editor, style) => {
toggleInlineStyleInSelection(editor, style);
};

export const toggleBlock = (editor, format) => {
// We have 6 boolean variables which need to be accounted for.
// See https://docs.google.com/spreadsheets/d/1mVeMuqSTMABV2BhoHPrPAFjn7zUksbNgZ9AQK_dcd3U/edit?usp=sharing
const { slate } = settings;
const { listTypes } = slate;

const isListItem = isBlockActive(editor, slate.listItemType);
const isActive = isBlockActive(editor, format);
const wantsList = listTypes.includes(format);

if (isListItem && !wantsList) {
toggleFormatAsListItem(editor, format);
} else if (isListItem && wantsList && !isActive) {
switchListType(editor, format); // this will deconstruct to Volto blocks
} else if (!isListItem && wantsList) {
changeBlockToList(editor, format);
} else if (!isListItem && !wantsList) {
toggleFormat(editor, format);
} else {
console.warn('toggleBlock case not covered, please examine:', {
wantsList,
isActive,
isListItem,
});
}
};

function toggleInlineStyleInSelection(editor, style) {
const m = Editor.marks(editor);
const keyName = 'style-' + style;

if (m && m[keyName]) {
Editor.removeMark(editor, keyName);
} else {
Editor.addMark(editor, keyName, true);
}
}

function toggleBlockStyleInSelection(editor, style) {
const sn = Array.from(
Editor.nodes(editor, {
mode: 'highest',
match: (n) => {
return !Editor.isEditor(n);
},
}),
);

for (const [n, p] of sn) {
let cn = n.styleName;
if (typeof n.styleName !== 'string') {
cn = style;
} else if (n.styleName.split(' ').filter((x) => x === style).length > 0) {
cn = cn
.split(' ')
.filter((x) => x !== style)
.join(' ');
} else {
// the style is not set but other styles are set
cn = cn.split(' ').concat(style).join(' ');
}
Transforms.setNodes(editor, { styleName: cn }, { at: p });
}
}

/*
* Toggles between list types by exploding the block
*/
export const switchListType = (editor, format) => {
const { slate } = settings;
Transforms.unwrapNodes(editor, {
match: (n) => slate.listTypes.includes(n.type),
split: true,
});
const block = { type: format, children: [] };
Transforms.wrapNodes(editor, block);

deconstructToVoltoBlocks(editor);
};

export const changeBlockToList = (editor, format) => {
const { slate } = settings;
const [match] = Editor.nodes(editor, {
match: (n) => n.type === slate.listItemType,
});

if (!match) {
Transforms.setNodes(editor, {
type: slate.listItemType,
// id: nanoid(8),
});
}
const block = { type: format, children: [] };
Transforms.wrapNodes(editor, block);
};

export const toggleFormat = (editor, format) => {
const { slate } = settings;
const isActive = isBlockActive(editor, format);
const type = isActive ? slate.defaultBlockType : format;
Transforms.setNodes(editor, {
type,
});
};
Loading

0 comments on commit cbb0779

Please sign in to comment.