numbering-xml.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. var _ = require("underscore");
  2. exports.readNumberingXml = readNumberingXml;
  3. exports.Numbering = Numbering;
  4. exports.defaultNumbering = new Numbering({}, {});
  5. function Numbering(nums, abstractNums, styles) {
  6. var allLevels = _.flatten(_.values(abstractNums).map(function(abstractNum) {
  7. return _.values(abstractNum.levels);
  8. }));
  9. var levelsByParagraphStyleId = _.indexBy(
  10. allLevels.filter(function(level) {
  11. return level.paragraphStyleId != null;
  12. }),
  13. "paragraphStyleId"
  14. );
  15. function findLevel(numId, level) {
  16. var num = nums[numId];
  17. if (num) {
  18. var abstractNum = abstractNums[num.abstractNumId];
  19. if (!abstractNum) {
  20. return null;
  21. } else if (abstractNum.numStyleLink == null) {
  22. return abstractNums[num.abstractNumId].levels[level];
  23. } else {
  24. var style = styles.findNumberingStyleById(abstractNum.numStyleLink);
  25. return findLevel(style.numId, level);
  26. }
  27. } else {
  28. return null;
  29. }
  30. }
  31. function findLevelByParagraphStyleId(styleId) {
  32. return levelsByParagraphStyleId[styleId] || null;
  33. }
  34. return {
  35. findLevel: findLevel,
  36. findLevelByParagraphStyleId: findLevelByParagraphStyleId
  37. };
  38. }
  39. function readNumberingXml(root, options) {
  40. if (!options || !options.styles) {
  41. throw new Error("styles is missing");
  42. }
  43. var abstractNums = readAbstractNums(root);
  44. var nums = readNums(root, abstractNums);
  45. return new Numbering(nums, abstractNums, options.styles);
  46. }
  47. function readAbstractNums(root) {
  48. var abstractNums = {};
  49. root.getElementsByTagName("w:abstractNum").forEach(function(element) {
  50. var id = element.attributes["w:abstractNumId"];
  51. abstractNums[id] = readAbstractNum(element);
  52. });
  53. return abstractNums;
  54. }
  55. function readAbstractNum(element) {
  56. var levels = {};
  57. element.getElementsByTagName("w:lvl").forEach(function(levelElement) {
  58. var levelIndex = levelElement.attributes["w:ilvl"];
  59. var numFmt = levelElement.firstOrEmpty("w:numFmt").attributes["w:val"];
  60. var paragraphStyleId = levelElement.firstOrEmpty("w:pStyle").attributes["w:val"];
  61. levels[levelIndex] = {
  62. isOrdered: numFmt !== "bullet",
  63. level: levelIndex,
  64. paragraphStyleId: paragraphStyleId
  65. };
  66. });
  67. var numStyleLink = element.firstOrEmpty("w:numStyleLink").attributes["w:val"];
  68. return {levels: levels, numStyleLink: numStyleLink};
  69. }
  70. function readNums(root) {
  71. var nums = {};
  72. root.getElementsByTagName("w:num").forEach(function(element) {
  73. var numId = element.attributes["w:numId"];
  74. var abstractNumId = element.first("w:abstractNumId").attributes["w:val"];
  75. nums[numId] = {abstractNumId: abstractNumId};
  76. });
  77. return nums;
  78. }