1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
var _ = require("underscore");
exports.readNumberingXml = readNumberingXml;
exports.Numbering = Numbering;
exports.defaultNumbering = new Numbering({}, {});
function Numbering(nums, abstractNums, styles) {
var allLevels = _.flatten(_.values(abstractNums).map(function(abstractNum) {
return _.values(abstractNum.levels);
}));
var levelsByParagraphStyleId = _.indexBy(
allLevels.filter(function(level) {
return level.paragraphStyleId != null;
}),
"paragraphStyleId"
);
function findLevel(numId, level) {
return findLevelWithSeenNumIds(numId, level, Object.create(null));
}
function findLevelWithSeenNumIds(numId, level, seenNumIds) {
if (seenNumIds[numId]) {
return null;
}
seenNumIds[numId] = true;
var num = nums[numId];
if (!num) {
return null;
}
var abstractNum = abstractNums[num.abstractNumId];
if (!abstractNum) {
return null;
} else if (abstractNum.numStyleLink == null) {
return abstractNums[num.abstractNumId].levels[level];
} else {
var style = styles.findNumberingStyleById(abstractNum.numStyleLink);
return findLevelWithSeenNumIds(style.numId, level, seenNumIds);
}
}
function findLevelByParagraphStyleId(styleId) {
return levelsByParagraphStyleId[styleId] || null;
}
return {
findLevel: findLevel,
findLevelByParagraphStyleId: findLevelByParagraphStyleId
};
}
function readNumberingXml(root, options) {
if (!options || !options.styles) {
throw new Error("styles is missing");
}
var abstractNums = readAbstractNums(root);
var nums = readNums(root, abstractNums);
return new Numbering(nums, abstractNums, options.styles);
}
function readAbstractNums(root) {
var abstractNums = Object.create(null);
root.getElementsByTagName("w:abstractNum").forEach(function(element) {
var id = element.attributes["w:abstractNumId"];
abstractNums[id] = readAbstractNum(element);
});
return abstractNums;
}
function readAbstractNum(element) {
var levels = Object.create(null);
// Some malformed documents define numbering levels without an index, and
// reference the numbering using a w:numPr element without a w:ilvl child.
// To handle such cases, we assume a level of 0 as a fallback.
var levelWithoutIndex = null;
element.getElementsByTagName("w:lvl").forEach(function(levelElement) {
var levelIndex = levelElement.attributes["w:ilvl"];
var numFmt = levelElement.firstOrEmpty("w:numFmt").attributes["w:val"];
var isOrdered = numFmt !== "bullet";
var paragraphStyleId = levelElement.firstOrEmpty("w:pStyle").attributes["w:val"];
if (levelIndex === undefined) {
levelWithoutIndex = {
isOrdered: isOrdered,
level: "0",
paragraphStyleId: paragraphStyleId
};
} else {
levels[levelIndex] = {
isOrdered: isOrdered,
level: levelIndex,
paragraphStyleId: paragraphStyleId
};
}
});
if (levelWithoutIndex !== null && levels[levelWithoutIndex.level] === undefined) {
levels[levelWithoutIndex.level] = levelWithoutIndex;
}
var numStyleLink = element.firstOrEmpty("w:numStyleLink").attributes["w:val"];
return {levels: levels, numStyleLink: numStyleLink};
}
function readNums(root) {
var nums = Object.create(null);
root.getElementsByTagName("w:num").forEach(function(element) {
var numId = element.attributes["w:numId"];
var abstractNumId = element.first("w:abstractNumId").attributes["w:val"];
nums[numId] = {abstractNumId: abstractNumId};
});
return nums;
}
|