1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-28 17:02:04 +03:00

Rolled out text alignment to other block types

Completed off alignment types and markdown handling in the process.
This commit is contained in:
Dan Brown
2022-01-12 10:18:06 +00:00
parent 6744ab2ff9
commit 717557df89
3 changed files with 102 additions and 44 deletions

View File

@ -4,10 +4,12 @@ import {docToHtml} from "./util";
const nodes = defaultMarkdownSerializer.nodes; const nodes = defaultMarkdownSerializer.nodes;
const marks = defaultMarkdownSerializer.marks; const marks = defaultMarkdownSerializer.marks;
nodes.callout = function(state, node) { nodes.callout = function(state, node) {
writeNodeAsHtml(state, node); writeNodeAsHtml(state, node);
}; };
marks.underline = { marks.underline = {
open: '<span style="text-decoration: underline;">', open: '<span style="text-decoration: underline;">',
close: '</span>', close: '</span>',
@ -28,12 +30,28 @@ marks.subscript = {
close: '</sub>', close: '</sub>',
}; };
function writeNodeAsHtml(state, node) { function writeNodeAsHtml(state, node) {
const html = docToHtml({ content: [node] }); const html = docToHtml({ content: [node] });
state.write(html); state.write(html);
state.ensureNewLine();
state.write('\n');
state.closeBlock(); state.closeBlock();
} }
// Update serializers to just write out as HTML if we have an attribute
// or element that cannot be represented in commonmark without losing
// formatting or content.
for (const [nodeType, serializerFunction] of Object.entries(nodes)) {
nodes[nodeType] = function(state, node) {
if (node.attrs.align) {
writeNodeAsHtml(state, node);
} else {
serializerFunction(state, node);
}
}
}
const serializer = new MarkdownSerializer(nodes, marks); const serializer = new MarkdownSerializer(nodes, marks);

View File

@ -1,20 +1,52 @@
import {orderedList, bulletList, listItem} from "prosemirror-schema-list"; import {orderedList, bulletList, listItem} from "prosemirror-schema-list";
const alignAttrFromDomNode = node => { /**
if (node.classList.contains('align-right')) { * @param {HTMLElement} node
return 'right'; * @return {string|null}
} */
if (node.classList.contains('align-left')) { function getAlignAttrFromDomNode(node) {
return 'left'; const classList = node.classList;
} const styles = node.style || {};
if (node.classList.contains('align-center')) { const alignments = ['right', 'left', 'center', 'justify'];
return 'center'; for (const alignment of alignments) {
} if (classList.contains('align-' + alignment) || styles.textAlign === alignment) {
if (node.classList.contains('align-justify')) { return alignment;
return 'justify'; }
} }
return null; return null;
}; }
/**
* @param {String} className
* @param {Object} attrs
* @return {Object}
*/
function addClassToAttrs(className, attrs) {
return Object.assign({}, attrs, {
class: attrs.class ? attrs.class + ' ' + className : className,
});
}
/**
* @param node
* @param {Object} attrs
* @return {Object}
*/
function addAlignmentAttr(node, attrs) {
const positions = ['right', 'left', 'center', 'justify'];
for (const position of positions) {
if (node.attrs.align === position) {
return addClassToAttrs('align-' + position, attrs);
}
}
return attrs;
}
function getAttrsParserForAlignment(node) {
return {
align: getAlignAttrFromDomNode(node),
};
}
const doc = { const doc = {
content: "block+", content: "block+",
@ -26,11 +58,7 @@ const paragraph = {
parseDOM: [ parseDOM: [
{ {
tag: "p", tag: "p",
getAttrs(node) { getAttrs: getAttrsParserForAlignment,
return {
align: alignAttrFromDomNode(node),
};
}
} }
], ],
attrs: { attrs: {
@ -39,14 +67,7 @@ const paragraph = {
} }
}, },
toDOM(node) { toDOM(node) {
const attrs = {}; return ["p", addAlignmentAttr(node, {}), 0];
if (node.attrs.align === 'right') {
attrs['class'] = 'align-right';
}
if (node.attrs.align === 'left') {
attrs['class'] = 'align-left';
}
return ["p", attrs, 0];
} }
}; };
@ -54,12 +75,14 @@ const blockquote = {
content: "block+", content: "block+",
group: "block", group: "block",
defining: true, defining: true,
parseDOM: [{tag: "blockquote"}], parseDOM: [{tag: "blockquote", getAttrs: getAttrsParserForAlignment}],
align: { attrs: {
default: null, align: {
default: null,
}
}, },
toDOM() { toDOM(node) {
return ["blockquote", 0]; return ["blockquote", addAlignmentAttr(node, {}), 0];
} }
}; };
@ -71,19 +94,27 @@ const horizontal_rule = {
} }
}; };
const headingParseGetAttrs = (level) => {
return function (node) {
return {level, align: getAlignAttrFromDomNode(node)};
};
};
const heading = { const heading = {
attrs: {level: {default: 1}, align: {default: null}}, attrs: {level: {default: 1}, align: {default: null}},
content: "inline*", content: "inline*",
group: "block", group: "block",
defining: true, defining: true,
parseDOM: [{tag: "h1", attrs: {level: 1}}, parseDOM: [
{tag: "h2", attrs: {level: 2}}, {tag: "h1", getAttrs: headingParseGetAttrs(1)},
{tag: "h3", attrs: {level: 3}}, {tag: "h2", getAttrs: headingParseGetAttrs(2)},
{tag: "h4", attrs: {level: 4}}, {tag: "h3", getAttrs: headingParseGetAttrs(3)},
{tag: "h5", attrs: {level: 5}}, {tag: "h4", getAttrs: headingParseGetAttrs(4)},
{tag: "h6", attrs: {level: 6}}], {tag: "h5", getAttrs: headingParseGetAttrs(5)},
{tag: "h6", getAttrs: headingParseGetAttrs(6)},
],
toDOM(node) { toDOM(node) {
return ["h" + node.attrs.level, 0] return ["h" + node.attrs.level, addAlignmentAttr(node, {}), 0]
} }
}; };
@ -140,6 +171,12 @@ const hard_break = {
} }
}; };
const calloutParseGetAttrs = (type) => {
return function (node) {
return {type, align: getAlignAttrFromDomNode(node)};
};
};
const callout = { const callout = {
attrs: { attrs: {
type: {default: 'info'}, type: {default: 'info'},
@ -149,15 +186,15 @@ const callout = {
group: "block", group: "block",
defining: true, defining: true,
parseDOM: [ parseDOM: [
{tag: 'p.callout.info', attrs: {type: 'info'}, priority: 75,}, {tag: 'p.callout.info', getAttrs: calloutParseGetAttrs('info'), priority: 75},
{tag: 'p.callout.success', attrs: {type: 'success'}, priority: 75,}, {tag: 'p.callout.success', getAttrs: calloutParseGetAttrs('success'), priority: 75},
{tag: 'p.callout.danger', attrs: {type: 'danger'}, priority: 75,}, {tag: 'p.callout.danger', getAttrs: calloutParseGetAttrs('danger'), priority: 75},
{tag: 'p.callout.warning', attrs: {type: 'warning'}, priority: 75,}, {tag: 'p.callout.warning', getAttrs: calloutParseGetAttrs('warning'), priority: 75},
{tag: 'p.callout', attrs: {type: 'info'}, priority: 75}, {tag: 'p.callout', getAttrs: calloutParseGetAttrs('info'), priority: 75},
], ],
toDOM(node) { toDOM(node) {
const type = node.attrs.type || 'info'; const type = node.attrs.type || 'info';
return ['p', {class: 'callout ' + type}, 0]; return ['p', addAlignmentAttr(node, {class: 'callout ' + type}) , 0];
} }
}; };

View File

@ -105,6 +105,9 @@ body.mce-fullscreen, body.markdown-fullscreen {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
.align-justify {
text-align: justify;
}
img { img {
max-width: 100%; max-width: 100%;
height:auto; height:auto;