Commit ebbcee67 authored by Christos's avatar Christos

Merge branch 'develop' into 'master'

Develop

See merge request !38
parents 7d3c8d8b e1feb983
......@@ -3,7 +3,6 @@ import styled, { createGlobalStyle, ThemeProvider } from "styled-components";
import { Wax } from "wax-prosemirror-core";
import { EditoriaLayout } from "wax-prosemirror-layouts";
import { cokoTheme } from "wax-prosemirror-themes";
import { schema, keys, plugins, rules } from "./EditorConfig";
......@@ -63,9 +62,7 @@ class Editoria extends Component {
user={user}
>
{({ editor, view, ...props }) => (
<ThemeProvider theme={cokoTheme}>
<EditoriaLayout editor={editor} view={view} {...props} />
</ThemeProvider>
<EditoriaLayout editor={editor} view={view} {...props} />
)}
</StyledWax>
</Fragment>
......
......@@ -3,14 +3,16 @@ import styled from "styled-components";
import { ButtonStyles } from "wax-prosemirror-themes";
const ButtonStyled = styled.button`
${ButtonStyles};
opacity: ${props => (props.select ? 1 : 0.4)};
pointer-events: ${props => (props.select ? "default" : "none")};
color: ${props =>
props.isActive ? props.theme.colorPrimary : props.theme.colorButton};
color: ${props => (props.isActive ? "white" : props.theme.colorButton)};
background-color: ${props =>
props.isActive ? props.theme.colorPrimary : "transparent"};
&:hover {
color: ${props => (props.isActive ? props.theme.colorPrimary : "#000")};
background-color: ${props =>
props.isActive ? props.theme.colorPrimary : "transparent"};
}
${ButtonStyles};
`;
const Button = ({ view = {}, item }) => (
......
const filtered = (menu, menuItems) =>
Object.keys(menu)
.filter(key => menuItems.includes(key))
.reduce((obj, key) => {
obj[key] = menu[key];
return obj;
}, {});
const setMenuItems = (allMenuItems, menuItems) => {
if (menuItems.length === 0) return allMenuItems;
return filtered(allMenuItems, menuItems);
};
export { setMenuItems };
import React from "react";
import styled from "styled-components";
import { forEach, map } from "lodash";
import { map } from "lodash";
import MainMenuBarItems from "./MainMenuBarItems";
import { setMenuItems } from "../helpers";
const MainMenuContainer = styled.div`
background: #fff;
......@@ -30,31 +31,7 @@ const MainMenu = styled.div`
background: transparent;
`;
const filtered = (menu, menuItems) =>
Object.keys(menu)
.filter(key => menuItems.includes(key))
.reduce((obj, key) => {
obj[key] = menu[key];
return obj;
}, {});
const setMenuItems = (menu, menuItems) => {
let items = menuItems;
if (menuItems.length === 0) {
forEach(menu, (key, index) => {
items.push(index);
});
}
return filtered(menu, items);
};
const MainMenuBar = ({
menuItems = [],
children,
view,
className,
fileUpload
}) => (
const MainMenuBar = ({ menuItems = [], view, className, fileUpload }) => (
<MainMenuContainer>
<MainMenuInner>
<MainMenu>
......
import React from "react";
import { v4 as uuid } from "uuid";
import {
joinUp,
lift,
......@@ -17,52 +16,18 @@ import { wrapInList } from "prosemirror-schema-list";
import icons from "../icons/icons";
//Components
import Button from "../components/button/Button";
import Button from "../components/Button";
import TableDropDown from "../components/TableDropDown";
import ImageUpload from "../components/ImageUpload";
import HeadingsDropDown from "../components/HeadingsDropDown";
const markActive = type => state => {
const { from, $from, to, empty } = state.selection;
return empty
? type.isInSet(state.storedMarks || $from.marks())
: state.doc.rangeHasMark(from, to, type);
};
const blockActive = (type, attrs = {}) => state => {
const { $from, to, node } = state.selection;
if (node) {
return node.hasMarkup(type, attrs);
}
return to <= $from.end() && $from.parent.hasMarkup(type, attrs);
};
const canInsert = type => state => {
const { $from } = state.selection;
for (let d = $from.depth; d >= 0; d--) {
const index = $from.index(d);
if ($from.node(d).canReplaceWith(index, index, type)) {
return true;
}
}
return false;
};
const promptForURL = () => {
let url = window && window.prompt("Enter the URL", "https://");
if (url && !/^https?:\/\//i.test(url)) {
url = "http://" + url;
}
return url;
};
import {
markActive,
blockActive,
canInsert,
promptForURL,
createTable
} from "./MainMenuCommands";
export default {
undo: {
......@@ -71,7 +36,7 @@ export default {
enable: undo,
run: undo,
select: state => true,
menu: props => <Button key={uuid()} {...props} />
menu: props => <Button key={uuid()} {...props} />
},
redo: {
title: "Redo last undone change",
......@@ -118,19 +83,19 @@ export default {
select: state => true,
menu: props => <Button key={uuid()} {...props} />
},
// small_caps: {
// title: "Toggle Small Caps",
// content: icons.small_caps,
// active: state => {
// return markActive(state.config.schema.marks.small_caps)(state);
// },
// run(state, dispatch) {
// toggleMark(state.config.schema.marks.small_caps)(state, dispatch);
// },
//
// select: state => true,
// menu: props => <Button key={uuid()} {...props} />
// },
small_caps: {
title: "Toggle Small Caps",
content: icons.small_caps,
active: state => {
return markActive(state.config.schema.marks.small_caps)(state);
},
run(state, dispatch) {
toggleMark(state.config.schema.marks.small_caps)(state, dispatch);
},
select: state => true,
menu: props => <Button key={uuid()} {...props} />
},
subscript: {
title: "Toggle subscript",
content: icons.subscript,
......@@ -204,8 +169,12 @@ export default {
blockquote: {
title: "Wrap in block quote",
content: icons.blockquote,
// active: blockActive(schema.nodes.blockquote),
// enable: wrapIn(schema.nodes.blockquote),
active: state => {
return blockActive(state.config.schema.nodes.blockquote)(state);
},
enable: state => {
return wrapIn(state.config.schema.nodes.blockquote)(state);
},
run(state, dispatch) {
wrapIn(state.config.schema.nodes.blockquote)(state, dispatch);
},
......@@ -215,8 +184,12 @@ export default {
bullet_list: {
title: "Wrap in bullet list",
content: icons.bullet_list,
// active: blockActive(schema.nodes.bullet_list),
// enable: wrapInList(schema.nodes.bullet_list),
active: state => {
return blockActive(state.config.schema.nodes.bullet_list)(state);
},
enable: state => {
return wrapInList(state.config.schema.nodes.bullet_list)(state);
},
run(state, dispatch) {
wrapInList(state.config.schema.nodes.bullet_list)(state, dispatch);
},
......@@ -226,8 +199,12 @@ export default {
ordered_list: {
title: "Wrap in ordered list",
content: icons.ordered_list,
// active: blockActive(schema.nodes.ordered_list),
// enable: wrapInList(schema.nodes.ordered_list),
active: state => {
return blockActive(state.config.schema.nodes.ordered_list)(state);
},
enable: state => {
return wrapInList(state.config.schema.nodes.ordered_list)(state);
},
run(state, dispatch) {
wrapInList(state.config.schema.nodes.ordered_list)(state, dispatch);
},
......@@ -254,7 +231,9 @@ export default {
image: {
title: "Insert image",
content: icons.image,
// enable: canInsert(schema.nodes.image),
enable: state => {
return canInsert(state.config.schema.nodes.image)(state);
},
select: state => true,
run: option => true,
menu: props => <ImageUpload key={uuid()} {...props} />
......@@ -262,26 +241,11 @@ export default {
table: {
title: "Insert table",
content: icons.table,
// enable: canInsert(schema.nodes.table),
enable: state => {
return canInsert(state.config.schema.nodes.table)(state);
},
run: (state, dispatch) => {
// const { from } = state.selection
let rowCount = window && window.prompt("How many rows?", 2);
let colCount = window && window.prompt("How many columns?", 2);
const cells = [];
while (colCount--) {
cells.push(state.config.schema.nodes.table_cell.createAndFill());
}
const rows = [];
while (rowCount--) {
rows.push(
state.config.schema.nodes.table_row.createAndFill(null, cells)
);
}
const table = state.config.schema.nodes.table.createAndFill(null, rows);
dispatch(state.tr.replaceSelectionWith(table));
return createTable(state, dispatch);
},
select: state => true,
menu: props => <Button key={uuid()} {...props} />
......
const markActive = type => state => {
const { from, $from, to, empty } = state.selection;
return empty
? type.isInSet(state.storedMarks || $from.marks())
: state.doc.rangeHasMark(from, to, type);
};
const blockActive = (type, attrs = {}) => state => {
const { $from, to, node } = state.selection;
if (node) {
return node.hasMarkup(type, attrs);
}
return to <= $from.end() && $from.parent.hasMarkup(type, attrs);
};
const canInsert = type => state => {
const { $from } = state.selection;
for (let d = $from.depth; d >= 0; d--) {
const index = $from.index(d);
if ($from.node(d).canReplaceWith(index, index, type)) {
return true;
}
}
return false;
};
const promptForURL = () => {
let url = window && window.prompt("Enter the URL", "https://");
if (url && !/^https?:\/\//i.test(url)) {
url = "http://" + url;
}
return url;
};
const createTable = (state, dispatch) => {
let rowCount = window && window.prompt("How many rows?", 2);
let colCount = window && window.prompt("How many columns?", 2);
const cells = [];
while (colCount--) {
cells.push(state.config.schema.nodes.table_cell.createAndFill());
}
const rows = [];
while (rowCount--) {
rows.push(state.config.schema.nodes.table_row.createAndFill(null, cells));
}
const table = state.config.schema.nodes.table.createAndFill(null, rows);
dispatch(state.tr.replaceSelectionWith(table));
};
export { markActive, blockActive, canInsert, promptForURL, createTable };
import React from "react";
import styled from "styled-components";
import { forEach, map } from "lodash";
import { map } from "lodash";
import SideMenuItems from "./SideMenuItems";
import { setMenuItems } from "../helpers";
const SideMenuContainer = styled.div`
display: flex;
......@@ -22,43 +23,19 @@ const SideMenu = styled.div`
margin-top: 15px;
button {
display: flex;
margin-left: 5%;
flex-direction: column;
font-family: ${props => props.theme.fontInterface};
margin-left: 5%;
width: 90%;
background: transparent;
}
`;
const filtered = (menu, menuItems) =>
Object.keys(menu)
.filter(key => menuItems.includes(key))
.reduce((obj, key) => {
obj[key] = menu[key];
return obj;
}, {});
const setMenuItems = (menu, menuItems) => {
let items = menuItems;
if (menuItems.length === 0) {
forEach(menu, (key, index) => {
items.push(index);
});
}
return filtered(menu, items);
};
const SideMenuBar = ({
menuItems = [],
children,
view,
className,
fileUpload
}) => (
const SideMenuBar = ({ menuItems = [], view, className }) => (
<SideMenuContainer>
<SideMenuInner>
<SideMenu>
{map(setMenuItems(SideMenuItems, menuItems), item =>
item.menu({ view, item, fileUpload })
item.menu({ view, item })
)}
</SideMenu>
</SideMenuInner>
......
const blockActive = (type, attrs = {}) => state => {
const { $from, to, node } = state.selection;
if (node) {
return node.hasMarkup(type, attrs);
}
return to <= $from.end() && $from.parent.hasMarkup(type, attrs);
};
export { blockActive };
......@@ -2,21 +2,13 @@ import React from "react";
import { v4 as uuid } from "uuid";
import { setBlockType } from "prosemirror-commands";
import Button from "../components/button/Button";
const blockActive = (type, attrs = {}) => state => {
const { $from, to, node } = state.selection;
if (node) {
return node.hasMarkup(type, attrs);
}
return to <= $from.end() && $from.parent.hasMarkup(type, attrs);
};
import Button from "../components/Button";
import { blockActive } from "./SideMenuItems";
export default {
title: {
title: "Change to Title",
content: "Title",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.title)(state);
},
......@@ -30,6 +22,7 @@ export default {
subtitle: {
title: "Change to Subtilte",
content: "Subtilte",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.subtitle)(state);
},
......@@ -42,6 +35,7 @@ export default {
author: {
title: "Change to Author",
content: "Author",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.author)(state);
},
......@@ -54,6 +48,7 @@ export default {
epigraphPoetry: {
title: "Change to Epigraph Poetry",
content: "Epigraph Poetry",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.epigraphPoetry)(state);
},
......@@ -66,6 +61,7 @@ export default {
epigraphProse: {
title: "Change to Epigraph Prose",
content: "Epigraph Prose",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.epigraphProse)(state);
},
......@@ -77,8 +73,8 @@ export default {
},
plain: {
title: "Change to General Text",
// content: icons.paragraph,
content: "General Text",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.paragraph)(state);
},
......@@ -92,6 +88,7 @@ export default {
heading1: {
title: "Change to heading level 1",
content: "Heading 1",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.heading, {
level: 1,
......@@ -110,6 +107,7 @@ export default {
heading2: {
title: "Change to heading level 2",
content: "Heading 2",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.heading, {
level: 2,
......@@ -128,6 +126,7 @@ export default {
heading3: {
title: "Change to heading level 3",
content: "Heading 3",
group: "",
enable: state => {
return setBlockType(state.config.schema.nodes.heading, {
level: 3,
......
......@@ -43,21 +43,21 @@ class Wax extends Component {
const { schema, plugins, keys, rules } = options;
const WaxOnchange = onChange ? onChange : value => true;
const WaxKeys =
options && options.keys
? options.keys
: new CreateShortCuts({ schema: schema, shortCuts: {} });
const WaxShortCuts = keys
? keys
: new CreateShortCuts({ schema: schema, shortCuts: {} });
const WaxRules = new CreateRules({ schema: schema, rules: rules });
const editorContent = value ? value : "";
if (plugins) defaultPlugins.push(...plugins);
const finalPlugins = defaultPlugins.concat([
placeholder({ content: this.props.placeholder }),
WaxKeys,
WaxShortCuts,
WaxRules
]);
if (plugins) finalPlugins.push(...plugins);
this.WaxOptions = {
schema,
......
......@@ -6,7 +6,6 @@ import { EditorView } from "prosemirror-view";
import placeholderPlugin from "./config/plugins/placeholderPlugin";
import "prosemirror-view/style/prosemirror.css";
import "prosemirror-gapcursor/style/gapcursor.css";
import trackedTransaction from "./config/track-changes/trackedTransaction";
class WaxView extends Component {
......
export { default as DefaultSchema } from "./src/DefaultSchema";
export { default as EditoriaSchema } from "./src/EditoriaSchema";
export { default as EditoriaSchema } from "./src/editoria/EditoriaSchema";
export { default as XpubSchema } from "./src/XpubSchema";
This diff is collapsed.
import nodes from "./nodes";
import marks from "./marks";
const EditoriaSchema = {
nodes,
marks
};
export default EditoriaSchema;
const parseFormatList = str => {
if (!str) {
return [];
}
let formatList;
try {
formatList = JSON.parse(str);
} catch (error) {
return [];
}
if (!Array.isArray(formatList)) {
return [];
}
return formatList.filter(format => typeof format === "string"); // ensure there are only strings in list
};
const parseTracks = str => {
if (!str) {
return [];
}
let tracks;
try {
tracks = JSON.parse(str);
} catch (error) {
return [];
}
if (!Array.isArray(tracks)) {
return [];
}
return tracks.filter(
(
track // ensure required fields are present
) =>
track.hasOwnProperty("user") &&
track.hasOwnProperty("username") &&
track.hasOwnProperty("date")
);
};
const blockLevelToDOM = node => {
const attrs = node.attrs.track.length
? {
class: node.attrs.class,
"data-track": JSON.stringify(node.attrs.track)
}
: { class: node.attrs.class };
return attrs;
};
export { parseFormatList, parseTracks, blockLevelToDOM };
const emDOM = ["em", 0],
strongDOM = ["strong", 0],
codeDOM = ["code", 0];
const marks = {
link: {
attrs: {
href: { default: null },
rel: { default: "" },
target: { default: "blank" },
title: { default: null }
},
inclusive: false,
parseDOM: [
{
tag: "a[href]",
getAttrs: dom => {
const href = dom.getAttribute("href");
const target = href && href.indexOf("#") === 0 ? "" : "blank";
return {
href: dom.getAttribute("href"),
title: dom.getAttribute("title"),
target
};
}
}
],
toDOM(node) {
return ["a", node.attrs, 0];
}
},
em: {
parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }],
toDOM() {
return emDOM;
}
},
strong: {
parseDOM: [
{ tag: "strong" },
{
tag: "b",
getAttrs: node => node.style.fontWeight != "normal" && null
},
{
style: "font-weight",
getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null
}
],
toDOM() {
return strongDOM;
}
},
code: {
parseDOM: [{ tag: "code" }],
toDOM() {
return codeDOM;
}
},
subscript: {
excludes: "superscript",
parseDOM: [{ tag: "sub" }, { style: "vertical-align=sub" }],
toDOM: () => ["sub"]
},
superscript: {
excludes: "subscript",
parseDOM: [{ tag: "sup" }, { style: "vertical-align=super" }],
toDOM: () => ["sup"]
},
strikethrough: {
parseDOM: [
{ tag: "strike" },
{ style: "text-decoration:line-through" },