Skip to content

Commit

Permalink
started separation rendering from parsing, implemented columns
Browse files Browse the repository at this point in the history
  • Loading branch information
VolodymyrBaydalka committed May 13, 2019
1 parent ae65184 commit f160bf1
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 76 deletions.
132 changes: 89 additions & 43 deletions src/document-parser.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { IDomStyle, IDomDocument, DomType, IDomTable, IDomStyleValues, IDomNumbering, IDomRun,
IDomHyperlink, IDomParagraph, IDomImage, IDomElement, IDomTableColumn, IDomTableCell,
IDomRelationship, IDomSubStyle, IDomTableRow, NumberingPicBullet, DocxTab, DomRelationshipType } from './dom';
import {
IDomStyle, DomType, IDomTable, IDomStyleValues, IDomNumbering, IDomRun,
IDomHyperlink, IDomParagraph, IDomImage, OpenXmlElement, IDomTableColumn, IDomTableCell,
IDomRelationship, IDomSubStyle, IDomTableRow, NumberingPicBullet, DocxTab, DomRelationshipType
} from './dom/dom';
import * as utils from './utils';
import { SectionProperties, WordDocument } from './dom/document';
import { namespaces, Columns } from './dom/common';
import { forEachElementNS, getAttributeLengthValue, getAttributeIntValue, getAttributeBoolValue } from './parser/common';

export var autos = {
shd: "white",
Expand All @@ -17,7 +23,7 @@ export class DocumentParser {
ignoreHeight: boolean = true;
debug: boolean = false;

parseDocumentRelationsFile(xmlString) {
parseDocumentRelationsFile(xmlString: string) {
var xrels = xml.parse(xmlString, this.skipDeclaration);

return xml.elements(xrels).map(c => <IDomRelationship>{
Expand All @@ -27,11 +33,12 @@ export class DocumentParser {
});
}

parseDocumentFile(xmlString) {
var result: IDomDocument = {
parseDocumentFile(xmlString: string) {
var result: WordDocument = {
domType: DomType.Document,
children: [],
style: {}
style: {},
section: null
};

var xbody = xml.byTagName(xml.parse(xmlString, this.skipDeclaration), "body");
Expand All @@ -47,7 +54,7 @@ export class DocumentParser {
break;

case "sectPr":
this.parseSectionProperties(elem, result);
result.section = this.parseSectionProperties(elem);
break;
}
});
Expand Down Expand Up @@ -189,8 +196,8 @@ export class DocumentParser {
var selector = "";

switch (type) {
case "firstRow": selector = "tr.first-row"; break;
case "lastRow": selector = "tr.last-row"; break;
case "firstRow": selector = "tr.first-row td"; break;
case "lastRow": selector = "tr.last-row td"; break;
case "firstCol": selector = "td.first-col"; break;
case "lastCol": selector = "td.last-col"; break;
case "band1Vert": selector = "td.odd-col"; break;
Expand Down Expand Up @@ -318,28 +325,63 @@ export class DocumentParser {
return result;
}

parseSectionProperties(elem: Element, domElem: IDomElement) {
xml.foreach(elem, n => {
switch (n.localName) {
case "pgMar":
domElem.style["padding-left"] = xml.sizeAttr(n, "left");
domElem.style["padding-right"] = xml.sizeAttr(n, "right");
domElem.style["padding-top"] = xml.sizeAttr(n, "top");
domElem.style["padding-bottom"] = xml.sizeAttr(n, "bottom");
break;
parseSectionProperties(elem: Element): SectionProperties {
var section = <SectionProperties>{};

forEachElementNS(elem, namespaces.wordml, e => {
switch(e.localName) {
case "pgSz":
if (!this.ignoreWidth)
domElem.style["width"] = xml.sizeAttr(n, "w");
section.pageSize = {
width: getAttributeLengthValue(e, namespaces.wordml, "w"),
height: getAttributeLengthValue(e, namespaces.wordml, "h"),
orientation: e.getAttributeNS(namespaces.wordml, "orient")
}
break;

case "pgMar":
section.pageMargins = {
left: getAttributeLengthValue(e, namespaces.wordml, "left"),
right: getAttributeLengthValue(e, namespaces.wordml, "right"),
top: getAttributeLengthValue(e, namespaces.wordml, "top"),
bottom: getAttributeLengthValue(e, namespaces.wordml, "bottom"),
header: getAttributeLengthValue(e, namespaces.wordml, "header"),
footer: getAttributeLengthValue(e, namespaces.wordml, "footer"),
gutter: getAttributeLengthValue(e, namespaces.wordml, "gutter"),
};
break;

if (!this.ignoreHeight)
domElem.style["height"] = xml.sizeAttr(n, "h");
case "cols":
section.columns = this.parseColumns(e);
break;
}
});

return section;
}

parseParagraph(node: Element): IDomElement {
parseColumns(elem: Element): Columns {
var result = {
numberOfColumns: getAttributeIntValue(elem, namespaces.wordml, "num"),
space: getAttributeLengthValue(elem, namespaces.wordml, "space"),
separator: getAttributeBoolValue(elem, namespaces.wordml, "sep"),
equalWidth: getAttributeBoolValue(elem, namespaces.wordml, "equalWidth", true),
columns: []
};

forEachElementNS(elem, namespaces.wordml, e => {
if(e.localName != "col")
return;

result.columns.push({
width: getAttributeLengthValue(elem, namespaces.wordml, "w"),
space: getAttributeLengthValue(elem, namespaces.wordml, "space")
});
});

return result;
}

parseParagraph(node: Element): OpenXmlElement {
var result = <IDomParagraph>{ domType: DomType.Paragraph, children: [] };

xml.foreach(node, c => {
Expand Down Expand Up @@ -369,7 +411,11 @@ export class DocumentParser {
this.parseDefaultProperties(elem, paragraph.style = {}, null, c => {
switch (c.localName) {
case "pStyle":
paragraph.className = xml.className(c, "val");
utils.addElementClass(paragraph, xml.className(c, "val"));
break;

case "cnfStyle":
utils.addElementClass(paragraph, values.classNameOfCnfStyle(c));
break;

case "numPr":
Expand Down Expand Up @@ -417,15 +463,15 @@ export class DocumentParser {
paragraph.style["float"] = "left";
}

parseBookmark(node: Element): IDomElement {
parseBookmark(node: Element): OpenXmlElement {
var result: IDomRun = { domType: DomType.Run };

result.id = xml.stringAttr(node, "name");

return result;
}

parseHyperlink(node: Element, parent?: IDomElement): IDomRun {
parseHyperlink(node: Element, parent?: OpenXmlElement): IDomRun {
var result: IDomHyperlink = { domType: DomType.Hyperlink, parent: parent, children: [] };
var anchor = xml.stringAttr(node, "anchor");

Expand All @@ -443,7 +489,7 @@ export class DocumentParser {
return result;
}

parseRun(node: Element, parent?: IDomElement): IDomRun {
parseRun(node: Element, parent?: OpenXmlElement): IDomRun {
var result: IDomRun = { domType: DomType.Run, parent: parent };

xml.foreach(node, c => {
Expand Down Expand Up @@ -499,7 +545,7 @@ export class DocumentParser {
});
}

parseDrawing(node: Element): IDomElement {
parseDrawing(node: Element): OpenXmlElement {
for (var n of xml.elements(node)) {
switch (n.localName) {
case "inline":
Expand All @@ -509,8 +555,8 @@ export class DocumentParser {
}
}

parseDrawingWrapper(node: Element): IDomElement {
var result = <IDomElement>{ domType: DomType.Drawing, children: [], style: {} };
parseDrawingWrapper(node: Element): OpenXmlElement {
var result = <OpenXmlElement>{ domType: DomType.Drawing, children: [], style: {} };
var isAnchor = node.localName == "anchor";

//TODO
Expand Down Expand Up @@ -582,7 +628,7 @@ export class DocumentParser {
return result;
}

parseGraphic(elem: Element): IDomElement {
parseGraphic(elem: Element): OpenXmlElement {
var graphicData = xml.byTagName(elem, "graphicData");

for (let n of xml.elements(graphicData)) {
Expand Down Expand Up @@ -670,6 +716,10 @@ export class DocumentParser {
table.className = xml.className(c, "val");
break;

case "tblLook":
utils.addElementClass(table, values.classNameOftblLook(c));
break;

case "tblpPr":
this.parseTablePosition(c, table);
break;
Expand Down Expand Up @@ -747,7 +797,7 @@ export class DocumentParser {
});
}

parseTableCell(node: Element): IDomElement {
parseTableCell(node: Element): OpenXmlElement {
var result: IDomTableCell = { domType: DomType.Cell, children: [] };

xml.foreach(node, c => {
Expand Down Expand Up @@ -1313,18 +1363,14 @@ class values {
}

static classNameOftblLook(c: Element) {
let val = xml.stringAttr(c, "val");
let num = parseInt(val, 16);
let className = "";
//FirstRow, LastRow, FirstColumn, LastColumn, Band1Vertical, Band2Vertical, Band1Horizontal, Band2Horizontal, NE Cell, NW Cell, SE Cell, SW Cell.

if (values.checkMask(num, 0x0020)) className += " first-row";
if (values.checkMask(num, 0x0040)) className += " last-row";
if (values.checkMask(num, 0x0080)) className += " first-col";
if (values.checkMask(num, 0x0100)) className += " last-col";

if (!values.checkMask(num, 0x0200)) className += " odd-row even-row";
if (!values.checkMask(num, 0x0400)) className += " odd-col even-col";
if (xml.boolAttr(c, "firstColumn")) className += " first-col";
if (xml.boolAttr(c, "firstRow")) className += " first-row";
if (xml.boolAttr(c, "lastColumn")) className += " lat-col";
if (xml.boolAttr(c, "lastRow")) className += " last-row";
if (xml.boolAttr(c, "noHBand")) className += " no-hband";
if (xml.boolAttr(c, "noVBand")) className += " no-vband";

return className.trim();
}
Expand Down
8 changes: 5 additions & 3 deletions src/document.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { DocumentParser } from './document-parser';
import { IDomRelationship, IDomStyle, IDomFont, IDomNumbering, IDomDocument } from './dom';
import { IDomRelationship, IDomStyle, IDomNumbering } from './dom/dom';
import { Font } from './dom/common';
import { WordDocument } from './dom/document';

enum PartType {
Document = "word/document.xml",
Expand All @@ -18,9 +20,9 @@ export class Document {
numRelations: IDomRelationship[] = null;

styles: IDomStyle[] = null;
fonts: IDomFont[] = null;
fonts: Font[] = null;
numbering: IDomNumbering[] = null;
document: IDomDocument = null;
document: WordDocument = null;

static load(blob, parser: DocumentParser): PromiseLike<Document> {
var d = new Document();
Expand Down
15 changes: 12 additions & 3 deletions src/docx-preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@ export function renderAsync(data: Blob | any, bodyContainer: HTMLElement, styleC
var parser = new DocumentParser();
var renderer = new HtmlRenderer(window.document);

options = {
ignoreHeight: true,
ignoreWidth: false,
debug: false,
className: "docx",
inWrapper: true,
... options
};

if (options) {
parser.ignoreWidth = options.ignoreWidth || parser.ignoreWidth;
parser.ignoreHeight = options.ignoreHeight || parser.ignoreHeight;
options.ignoreWidth = options.ignoreWidth || parser.ignoreWidth;
options.ignoreHeight = options.ignoreHeight || parser.ignoreHeight;
parser.debug = options.debug || parser.debug;

renderer.className = options.className || "docx";
Expand All @@ -25,7 +34,7 @@ export function renderAsync(data: Blob | any, bodyContainer: HTMLElement, styleC

return Document.load(data, parser)
.then(doc => {
renderer.render(doc, bodyContainer, styleContainer);
renderer.render(doc, bodyContainer, styleContainer, options);
return doc;
});
}
26 changes: 26 additions & 0 deletions src/dom/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const namespaces = {
wordml: "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
}

export interface Length {
value: number;
type: "px" | "pt" | "%"
}

export interface Font {
name: string;
family: string;
}

export interface Column {
space: Length;
width: Length;
}

export interface Columns {
space: Length;
numberOfColumns: number;
separator: boolean;
equalWidth: boolean;
columns: Column[];
}
28 changes: 28 additions & 0 deletions src/dom/document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Length, Columns } from "./common";
import { OpenXmlElement } from "./dom";

export interface PageSize {
width: Length,
height: Length,
orientation: "landscape" | string
}

export interface PageMargins {
top: Length;
right: Length;
bottom: Length;
left: Length;
header: Length;
footer: Length;
gutter: Length;
}

export interface SectionProperties {
pageSize: PageSize,
pageMargins: PageMargins,
columns: Columns;
}

export interface WordDocument extends OpenXmlElement {
section: SectionProperties;
}
Loading

0 comments on commit f160bf1

Please sign in to comment.