Skip to content
Snippets Groups Projects

Counters

Merged Christos requested to merge counters into master
1 file
+ 120
367
Compare changes
  • Side-by-side
  • Inline
/* eslint-disable react/prop-types */
import React, {
useMemo,
useState,
useRef,
useContext,
useEffect,
useCallback,
} from 'react';
import React, { useMemo, useState, useRef, useContext, useEffect } from 'react';
import styled from 'styled-components';
import { isEmpty } from 'lodash';
import { useTranslation } from 'react-i18next';
import { grid, override } from '@pubsweet/ui-toolkit';
import { v4 as uuidv4 } from 'uuid';
import {
WaxContext,
DocumentHelpers,
useOnClickOutside,
MenuButton,
useOnClickOutside,
WaxContext,
} from 'wax-prosemirror-core';
import { isEmpty } from 'lodash';
import { useTranslation } from 'react-i18next';
const Wrapper = styled.div`
font-size: 0;
@@ -48,6 +39,8 @@ const Wrapper = styled.div`
position: relative;
width: 0;
}
/* stylelint-disable-next-line order/properties-alphabetical-order */
${override('Wax.CounterWrapper')}
`;
@@ -57,6 +50,8 @@ const DropWrapper = styled.div`
position: absolute;
top: 32px;
width: max-content;
/* stylelint-disable-next-line order/properties-alphabetical-order */
${override('Wax.CounterDropWrapper')}
`;
@@ -73,6 +68,8 @@ const CounterInfoComponent = styled.div`
position: fixed;
right: 31px;
transform-origin: 50% 50% 0px;
/* stylelint-disable-next-line order/properties-alphabetical-order */
${override('Wax.CounterInfoComponent')}
`;
@@ -83,399 +80,155 @@ const Counter = styled.div`
height: 25px;
margin: 5px;
min-width: 150px;
/* stylelint-disable-next-line order/properties-alphabetical-order */
${override('Wax.Counters')}
`;
/* TODO Rewrite all of this */
const EditorInfoTool = ({ view: { state }, item }) => {
const { title } = item;
const [isOpen, setIsOpen] = useState(false);
const [getWordCountFromState, setTotalWords] = useState(0);
const [totalCharCount, setTotalCharCount] = useState();
const [totalCharCountWithoutSpace, setTotalCharWithoutSpace] = useState();
const [getSelectionCountFromState, setSelectedTextCount] = useState();
const [paraCount, setTotalParagraph] = useState();
const [imgCount, setImgCount] = useState();
const [tableCount, setTableCount] = useState();
const [footnoteCount, setFootNoteCount] = useState();
const [blocklevelNode, setBlockLevelNodes] = useState();
const ref = useRef();
const {
activeView,
pmViews: { main },
} = useContext(WaxContext);
const allBlockNodes = DocumentHelpers.findBlockNodes(main.state.doc);
const InlineNodes = DocumentHelpers.findInlineNodes(main.state.doc);
useOnClickOutside(ref, () => setIsOpen(false));
const { t, i18n } = useTranslation();
const ref = useRef();
const [currentWordCount, setCurrentWordCount] = useState(0);
const [isOpen, setIsOpen] = useState(false);
useOnClickOutside(ref, () => setIsOpen(false));
const infoDropDownOptions = [
{
name: `${getWordCountFromState} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Words`)
? t(`Wax.Counters.Words`)
: 'Words'
}`,
},
{
name: `${totalCharCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Characters`)
? t(`Wax.Counters.Characters`)
: 'Characters'
}`,
},
{
name: `${totalCharCountWithoutSpace} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Characters Without Space`)
? t(`Wax.Counters.Characters Without Space`)
: 'Characters Without Space'
}`,
},
{
name: `${paraCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Paragraph`)
? t(`Wax.Counters.Paragraph`)
: 'Paragraph'
}`,
},
{
name: `${imgCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Images`)
? t(`Wax.Counters.Images`)
: 'Images'
}`,
},
{
name: `${tableCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Tables`)
? t(`Wax.Counters.Tables`)
: 'Tables'
}`,
},
{
name: `${footnoteCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Footnotes`)
? t(`Wax.Counters.Footnotes`)
: 'Footnotes'
}`,
},
{
name: `${blocklevelNode} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Block-Level Nodes`)
? t(`Wax.Counters.Block-Level Nodes`)
: 'Block-Level Nodes'
}`,
},
];
const renderList = () => {
const lists = [];
Object.keys(infoDropDownOptions).forEach(key => {
lists.push(
<Counter key={uuidv4()} title={infoDropDownOptions[key].name}>
<span>{infoDropDownOptions[key].name}</span>
</Counter>,
);
});
return <div>{lists}</div>;
};
const getCount = useCallback(() => {
let getWordCountFromStates = 0;
InlineNodes.forEach(value => {
if (value.node.text !== undefined && value.node.text.length > 0) {
value.node.text
.trim()
.split(' ')
.forEach((key, pos) => {
if (key.length > 0) {
getWordCountFromStates += 1;
}
});
}
});
return getWordCountFromStates;
});
useEffect(() => {
const { from, to } = activeView.state.selection;
const currentSelection = activeView.state.doc.textBetween(from, to);
setCurrentWordCount(
currentSelection.split(' ').filter(word => word !== '').length,
);
}, [activeView.state.selection]);
const infoDropDownOptions = () => {
const docText = main.state.doc.textBetween(
0,
main.state.doc.content.size,
undefined,
' ',
);
const getCharCount = useCallback(() => {
let totalCharCounts = 0;
const chars = docText.split('');
const wordCount = docText.split(' ').filter(word => word !== '').length;
const characterCount = chars.length;
const charactersNoSpaceCount = chars.filter(char => char !== ' ').length;
InlineNodes.forEach(value => {
if (value.node.text !== undefined) {
totalCharCounts += value.node.text.length;
}
});
let paragraphCount = 0;
let imageCount = 0;
let footnoteCount = 0;
let tableCount = 0;
return totalCharCounts;
});
const getCharCountWithoutSpace = useCallback(() => {
let totalCharCountWithoutSpaces = 0;
InlineNodes.forEach(value => {
if (value.node.text !== undefined) {
totalCharCountWithoutSpaces += value.node.text.replace(/\s+/g, '')
.length;
state.doc.descendants(node => {
if (node.type.name === 'paragraph') {
paragraphCount += 1;
}
});
return totalCharCountWithoutSpaces;
});
useEffect(() => {
let footNoteCount = 0;
let blockLevelCount = 0;
let paraCounts = 0;
let tableCounts = 0;
let imgCounts = 0;
let listTableCount = 0;
let nestTableCount = 0;
allBlockNodes.forEach(value => {
if (value.pos === 0) {
blockLevelCount = 0;
} else {
blockLevelCount = allBlockNodes.length;
if (node.type.name === 'image') {
imageCount += 1;
}
});
setBlockLevelNodes(blockLevelCount);
allBlockNodes.forEach(nodes => {
nodes.node.forEach(node => {
if (node.type.name === 'image') {
imgCounts += 1;
}
if (node.type.groups.includes('notes')) {
footNoteCount += 1;
}
});
});
main.state.doc.content.content.forEach(value => {
if (value.attrs.class === 'paragraph' && value.content.size > 0) {
paraCounts += 1;
if (node.type.groups.includes('notes')) {
footnoteCount += 1;
}
if (value.type.name === 'table') {
tableCounts += 1;
if (node.type.name === 'table') {
tableCount += 1;
}
value.content.content.forEach(listTable => {
listTable.content.content.forEach(lastListTable => {
if (lastListTable.type.name === 'table') {
listTableCount += 1;
}
lastListTable.content.content.forEach(nestedTable => {
nestedTable.content.content.forEach(nestedTypeTable => {
if (nestedTypeTable.type.name === 'table') {
nestTableCount += 1;
}
});
});
});
});
});
setImgCount(imgCounts);
setTotalParagraph(paraCounts);
setTableCount(tableCounts + listTableCount + nestTableCount);
setFootNoteCount(footNoteCount);
setTotalCharCount(getCharCount());
setTotalWords(getCount());
setTotalCharWithoutSpace(getCharCountWithoutSpace());
let selectedCountPara = 0;
let selectedCountList = 0;
let selectedCountNest = 0;
let noteTextValue = 0;
let footNodeCount = 0;
let selectedListTableCount = 0;
let finalNestedValueCount = 0;
state.selection.content().content.content.forEach(value => {
value.content.content.forEach(textValue => {
if (textValue.text) {
const textArray = textValue.text.trim().split(' ');
let isChar = false;
textArray.forEach((key, pos) => {
// eslint-disable-next-line no-restricted-globals
if (
key.charCodeAt(pos) !== 32 &&
isNaN(key.charCodeAt(pos)) === false
) {
isChar = true;
}
});
if (isChar) {
selectedCountPara += textValue.text.trim().split(' ').length;
}
}
textValue.content.content.forEach(listValue => {
if (listValue.text && listValue.text !== ' ') {
const listArray = listValue.text.trim().split(' ');
let isFootChar = false;
listArray.forEach((key, pos) => {
if (key.charCodeAt(pos) !== 32) {
isFootChar = true;
}
});
if (isFootChar) {
footNodeCount += listValue.text.trim().split(' ').length;
}
}
listValue.content.content.forEach(listItem => {
if (listItem.text && listItem.text !== ' ') {
const itemArray = listItem.text.trim().split(' ');
let isItemChar = false;
itemArray.forEach((key, pos) => {
// eslint-disable-next-line no-restricted-globals
if (
key.charCodeAt(pos) !== 32 &&
isNaN(key.charCodeAt(pos)) === false
) {
isItemChar = true;
}
});
if (isItemChar) {
selectedCountList += listItem.text.trim().split(' ').length;
}
}
listItem.content.content.forEach(nestedItem => {
nestedItem.content.content.forEach(nestIn => {
if (nestIn.text !== undefined) {
const nestArray = nestIn.text.trim().split(' ');
let isNestChar = false;
nestArray.forEach((key, pos) => {
// eslint-disable-next-line no-restricted-globals
if (
key.charCodeAt(pos) !== 32 &&
isNaN(key.charCodeAt(pos)) === false
) {
isNestChar = true;
}
});
if (nestIn.text && isNestChar) {
selectedCountNest += nestIn.text.trim().split(' ').length;
}
}
nestIn.content.content.forEach(listTable => {
if (listTable.text !== undefined) {
const listTableArray = listTable.text.trim().split(' ');
let isListChar = false;
listTableArray.forEach((key, pos) => {
// eslint-disable-next-line no-restricted-globals
if (
key.charCodeAt(pos) !== 32 &&
isNaN(key.charCodeAt(pos)) === false
) {
isListChar = true;
}
});
if (listTable.text && isListChar) {
selectedListTableCount += listTable.text.trim().split(' ')
.length;
}
}
return [
{
name: `${wordCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Words`)
? t(`Wax.Counters.Words`)
: 'Words'
}`,
},
{
name: `${characterCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Characters`)
? t(`Wax.Counters.Characters`)
: 'Characters'
}`,
},
{
name: `${charactersNoSpaceCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Characters Without Space`)
? t(`Wax.Counters.Characters Without Space`)
: 'Characters Without Space'
}`,
},
{
name: `${paragraphCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Paragraph`)
? t(`Wax.Counters.Paragraph`)
: 'Paragraph'
}`,
},
{
name: `${imageCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Images`)
? t(`Wax.Counters.Images`)
: 'Images'
}`,
},
{
name: `${tableCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Tables`)
? t(`Wax.Counters.Tables`)
: 'Tables'
}`,
},
{
name: `${footnoteCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Footnotes`)
? t(`Wax.Counters.Footnotes`)
: 'Footnotes'
}`,
},
];
};
listTable.content.content.forEach(tableValue => {
tableValue.content.content.forEach(finalTableValue => {
if (finalTableValue.text !== undefined) {
const finalTableArray = finalTableValue.text
.trim()
.split(' ');
let isFinalTable = false;
finalTableArray.forEach((key, pos) => {
// eslint-disable-next-line no-restricted-globals
if (
key.charCodeAt(pos) !== 32 &&
isNaN(key.charCodeAt(pos)) === false
) {
isFinalTable = true;
}
});
if (finalNestedValueCount.text && isFinalTable) {
finalNestedValueCount = finalTableValue.text
.trim()
.split(' ').length;
}
}
});
});
});
});
});
});
});
});
if (value.text !== undefined) {
const valueArray = value.text.trim().split(' ');
let isValue = false;
valueArray.forEach((key, pos) => {
// eslint-disable-next-line no-restricted-globals
if (
key.charCodeAt(pos) !== 32 &&
isNaN(key.charCodeAt(pos)) === false
) {
isValue = true;
}
});
if (isValue) {
noteTextValue += value.text.trim().split(' ').length;
}
}
});
setSelectedTextCount(
selectedCountNest +
finalNestedValueCount +
selectedListTableCount +
selectedCountPara +
selectedCountList +
noteTextValue +
footNodeCount,
);
if (
activeView.state.selection.$from.pos ===
activeView.state.selection.$to.pos
) {
setSelectedTextCount(0);
}
});
const MenuButtonComponent = useMemo(
() => (
<Wrapper active={isOpen} ref={ref}>
<MenuButton
active={isOpen}
disabled={false}
label={`${
getSelectionCountFromState > 0
? getSelectionCountFromState
: getWordCountFromState
}
${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Word`)
? t(`Wax.Counters.Word`)
: 'Word'
}${
getSelectionCountFromState && getSelectionCountFromState > 1
? 's'
: ''
}${
!getSelectionCountFromState && getWordCountFromState > 1 ? 's' : ''
}`}
onMouseDown={() => {
label={`${currentWordCount} ${
!isEmpty(i18n) && i18n.exists(`Wax.Counters.Word`)
? t(`Wax.Counters.Word`)
: 'Word'
}${currentWordCount > 1 ? 's' : ''}
`}
onMouseDown={e => {
e.preventDefault();
setIsOpen(!isOpen);
}}
title={title}
title={item.title}
/>
{isOpen && (
<DropWrapper>
<CounterInfoComponent
close={() => {
setIsOpen(false);
}}
close={() => setIsOpen(false)}
item={item}
key={uuidv4()}
view={state}
>
{renderList()}
{infoDropDownOptions().map(option => (
<Counter key={option.name} title={option.name}>
<span>{option.name}</span>
</Counter>
))}
</CounterInfoComponent>
</DropWrapper>
)}
</Wrapper>
),
[isOpen, getWordCountFromState, getSelectionCountFromState],
[currentWordCount, isOpen],
);
return MenuButtonComponent;
};