docx-preview.js 130 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jszip')) :
  3. typeof define === 'function' && define.amd ? define(['exports', 'jszip'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.docx = {}, global.JSZip));
  5. })(this, (function (exports, JSZip) {
  6. 'use strict';
  7. var RelationshipTypes;
  8. (function (RelationshipTypes) {
  9. RelationshipTypes["OfficeDocument"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
  10. RelationshipTypes["FontTable"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
  11. RelationshipTypes["Image"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
  12. RelationshipTypes["Numbering"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
  13. RelationshipTypes["Styles"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
  14. RelationshipTypes["StylesWithEffects"] = "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects";
  15. RelationshipTypes["Theme"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
  16. RelationshipTypes["Settings"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
  17. RelationshipTypes["WebSettings"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
  18. RelationshipTypes["Hyperlink"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
  19. RelationshipTypes["Footnotes"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
  20. RelationshipTypes["Endnotes"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
  21. RelationshipTypes["Footer"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
  22. RelationshipTypes["Header"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
  23. RelationshipTypes["ExtendedProperties"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
  24. RelationshipTypes["CoreProperties"] = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
  25. RelationshipTypes["CustomProperties"] = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/custom-properties";
  26. RelationshipTypes["Comments"] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
  27. RelationshipTypes["CommentsExtended"] = "http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
  28. })(RelationshipTypes || (RelationshipTypes = {}));
  29. function parseRelationships (root, xml) {
  30. return xml.elements(root).map(e => ({
  31. id: xml.attr(e, "Id"),
  32. type: xml.attr(e, "Type"),
  33. target: xml.attr(e, "Target"),
  34. targetMode: xml.attr(e, "TargetMode")
  35. }));
  36. }
  37. const ns$1 = {
  38. wordml: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
  39. drawingml: "http://schemas.openxmlformats.org/drawingml/2006/main",
  40. picture: "http://schemas.openxmlformats.org/drawingml/2006/picture",
  41. compatibility: "http://schemas.openxmlformats.org/markup-compatibility/2006",
  42. math: "http://schemas.openxmlformats.org/officeDocument/2006/math"
  43. };
  44. const LengthUsage = {
  45. Dxa: { mul: 0.05, unit: "pt" },
  46. Emu: { mul: 1 / 12700, unit: "pt" },
  47. FontSize: { mul: 0.5, unit: "pt" },
  48. Border: { mul: 0.125, unit: "pt" },
  49. Point: { mul: 1, unit: "pt" },
  50. Percent: { mul: 0.02, unit: "%" },
  51. LineHeight: { mul: 1 / 240, unit: "" },
  52. VmlEmu: { mul: 1 / 12700, unit: "" },
  53. };
  54. function convertLength (val, usage = LengthUsage.Dxa) {
  55. if (val == null || /.+(p[xt]|[%])$/.test(val)) {
  56. return val;
  57. }
  58. return `${(parseInt(val) * usage.mul).toFixed(2)}${usage.unit}`;
  59. }
  60. function convertBoolean (v, defaultValue = false) {
  61. switch (v) {
  62. case "1": return true;
  63. case "0": return false;
  64. case "on": return true;
  65. case "off": return false;
  66. case "true": return true;
  67. case "false": return false;
  68. default: return defaultValue;
  69. }
  70. }
  71. function parseCommonProperty (elem, props, xml) {
  72. if (elem.namespaceURI != ns$1.wordml)
  73. return false;
  74. switch (elem.localName) {
  75. case "color":
  76. props.color = xml.attr(elem, "val");
  77. break;
  78. case "sz":
  79. props.fontSize = xml.lengthAttr(elem, "val", LengthUsage.FontSize);
  80. break;
  81. default:
  82. return false;
  83. }
  84. return true;
  85. }
  86. function parseXmlString (xmlString, trimXmlDeclaration = false) {
  87. if (trimXmlDeclaration)
  88. xmlString = xmlString.replace(/<[?].*[?]>/, "");
  89. xmlString = removeUTF8BOM(xmlString);
  90. const result = new DOMParser().parseFromString(xmlString, "application/xml");
  91. const errorText = hasXmlParserError(result);
  92. if (errorText)
  93. throw new Error(errorText);
  94. return result;
  95. }
  96. function hasXmlParserError (doc) {
  97. return doc.getElementsByTagName("parsererror")[0]?.textContent;
  98. }
  99. function removeUTF8BOM (data) {
  100. return data.charCodeAt(0) === 0xFEFF ? data.substring(1) : data;
  101. }
  102. function serializeXmlString (elem) {
  103. return new XMLSerializer().serializeToString(elem);
  104. }
  105. class XmlParser {
  106. elements (elem, localName = null) {
  107. const result = [];
  108. for (let i = 0, l = elem.childNodes.length; i < l; i++) {
  109. let c = elem.childNodes.item(i);
  110. if (c.nodeType == 1 && (localName == null || c.localName == localName))
  111. result.push(c);
  112. }
  113. return result;
  114. }
  115. element (elem, localName) {
  116. for (let i = 0, l = elem.childNodes.length; i < l; i++) {
  117. let c = elem.childNodes.item(i);
  118. if (c.nodeType == 1 && c.localName == localName)
  119. return c;
  120. }
  121. return null;
  122. }
  123. elementAttr (elem, localName, attrLocalName) {
  124. var el = this.element(elem, localName);
  125. return el ? this.attr(el, attrLocalName) : undefined;
  126. }
  127. attrs (elem) {
  128. return Array.from(elem.attributes);
  129. }
  130. attr (elem, localName) {
  131. for (let i = 0, l = elem.attributes.length; i < l; i++) {
  132. let a = elem.attributes.item(i);
  133. if (a.localName == localName)
  134. return a.value;
  135. }
  136. return null;
  137. }
  138. intAttr (node, attrName, defaultValue = null) {
  139. var val = this.attr(node, attrName);
  140. return val ? parseInt(val) : defaultValue;
  141. }
  142. hexAttr (node, attrName, defaultValue = null) {
  143. var val = this.attr(node, attrName);
  144. return val ? parseInt(val, 16) : defaultValue;
  145. }
  146. floatAttr (node, attrName, defaultValue = null) {
  147. var val = this.attr(node, attrName);
  148. return val ? parseFloat(val) : defaultValue;
  149. }
  150. boolAttr (node, attrName, defaultValue = null) {
  151. return convertBoolean(this.attr(node, attrName), defaultValue);
  152. }
  153. lengthAttr (node, attrName, usage = LengthUsage.Dxa) {
  154. return convertLength(this.attr(node, attrName), usage);
  155. }
  156. }
  157. const globalXmlParser = new XmlParser();
  158. class Part {
  159. constructor(_package, path) {
  160. this._package = _package;
  161. this.path = path;
  162. }
  163. async load () {
  164. this.rels = await this._package.loadRelationships(this.path);
  165. const xmlText = await this._package.load(this.path);
  166. const xmlDoc = this._package.parseXmlDocument(xmlText);
  167. if (this._package.options.keepOrigin) {
  168. this._xmlDocument = xmlDoc;
  169. }
  170. this.parseXml(xmlDoc.firstElementChild);
  171. }
  172. save () {
  173. this._package.update(this.path, serializeXmlString(this._xmlDocument));
  174. }
  175. parseXml (root) {
  176. }
  177. }
  178. const embedFontTypeMap = {
  179. embedRegular: 'regular',
  180. embedBold: 'bold',
  181. embedItalic: 'italic',
  182. embedBoldItalic: 'boldItalic',
  183. };
  184. function parseFonts (root, xml) {
  185. return xml.elements(root).map(el => parseFont(el, xml));
  186. }
  187. function parseFont (elem, xml) {
  188. let result = {
  189. name: xml.attr(elem, "name"),
  190. embedFontRefs: []
  191. };
  192. for (let el of xml.elements(elem)) {
  193. switch (el.localName) {
  194. case "family":
  195. result.family = xml.attr(el, "val");
  196. break;
  197. case "altName":
  198. result.altName = xml.attr(el, "val");
  199. break;
  200. case "embedRegular":
  201. case "embedBold":
  202. case "embedItalic":
  203. case "embedBoldItalic":
  204. result.embedFontRefs.push(parseEmbedFontRef(el, xml));
  205. break;
  206. }
  207. }
  208. return result;
  209. }
  210. function parseEmbedFontRef (elem, xml) {
  211. return {
  212. id: xml.attr(elem, "id"),
  213. key: xml.attr(elem, "fontKey"),
  214. type: embedFontTypeMap[elem.localName]
  215. };
  216. }
  217. class FontTablePart extends Part {
  218. parseXml (root) {
  219. this.fonts = parseFonts(root, this._package.xmlParser);
  220. }
  221. }
  222. function escapeClassName (className) {
  223. return className?.replace(/[ .]+/g, '-').replace(/[&]+/g, 'and').toLowerCase();
  224. }
  225. function splitPath (path) {
  226. let si = path.lastIndexOf('/') + 1;
  227. let folder = si == 0 ? "" : path.substring(0, si);
  228. let fileName = si == 0 ? path : path.substring(si);
  229. return [folder, fileName];
  230. }
  231. function resolvePath (path, base) {
  232. try {
  233. const prefix = "http://docx/";
  234. const url = new URL(path, prefix + base).toString();
  235. return url.substring(prefix.length);
  236. }
  237. catch {
  238. return `${base}${path}`;
  239. }
  240. }
  241. function keyBy (array, by) {
  242. return array.reduce((a, x) => {
  243. a[by(x)] = x;
  244. return a;
  245. }, {});
  246. }
  247. function blobToBase64 (blob) {
  248. return new Promise((resolve, reject) => {
  249. const reader = new FileReader();
  250. reader.onloadend = () => resolve(reader.result);
  251. reader.onerror = () => reject();
  252. reader.readAsDataURL(blob);
  253. });
  254. }
  255. function isObject (item) {
  256. return item && typeof item === 'object' && !Array.isArray(item);
  257. }
  258. function isString (item) {
  259. return typeof item === 'string' || item instanceof String;
  260. }
  261. function mergeDeep (target, ...sources) {
  262. if (!sources.length)
  263. return target;
  264. const source = sources.shift();
  265. if (isObject(target) && isObject(source)) {
  266. for (const key in source) {
  267. if (isObject(source[key])) {
  268. const val = target[key] ?? (target[key] = {});
  269. mergeDeep(val, source[key]);
  270. }
  271. else {
  272. target[key] = source[key];
  273. }
  274. }
  275. }
  276. return mergeDeep(target, ...sources);
  277. }
  278. function asArray (val) {
  279. return Array.isArray(val) ? val : [val];
  280. }
  281. class OpenXmlPackage {
  282. constructor(_zip, options) {
  283. this._zip = _zip;
  284. this.options = options;
  285. this.xmlParser = new XmlParser();
  286. }
  287. get (path) {
  288. const p = normalizePath(path);
  289. return this._zip.files[p] ?? this._zip.files[p.replace(/\//g, '\\')];
  290. }
  291. update (path, content) {
  292. this._zip.file(path, content);
  293. }
  294. static async load (input, options) {
  295. const zip = await JSZip.loadAsync(input);
  296. return new OpenXmlPackage(zip, options);
  297. }
  298. save (type = "blob") {
  299. return this._zip.generateAsync({ type });
  300. }
  301. load (path, type = "string") {
  302. return this.get(path)?.async(type) ?? Promise.resolve(null);
  303. }
  304. async loadRelationships (path = null) {
  305. let relsPath = `_rels/.rels`;
  306. if (path != null) {
  307. const [f, fn] = splitPath(path);
  308. relsPath = `${f}_rels/${fn}.rels`;
  309. }
  310. const txt = await this.load(relsPath);
  311. return txt ? parseRelationships(this.parseXmlDocument(txt).firstElementChild, this.xmlParser) : null;
  312. }
  313. parseXmlDocument (txt) {
  314. return parseXmlString(txt, this.options.trimXmlDeclaration);
  315. }
  316. }
  317. function normalizePath (path) {
  318. return path.startsWith('/') ? path.substr(1) : path;
  319. }
  320. class DocumentPart extends Part {
  321. constructor(pkg, path, parser) {
  322. super(pkg, path);
  323. this._documentParser = parser;
  324. }
  325. parseXml (root) {
  326. this.body = this._documentParser.parseDocumentFile(root);
  327. }
  328. }
  329. function parseBorder (elem, xml) {
  330. return {
  331. type: xml.attr(elem, "val"),
  332. color: xml.attr(elem, "color"),
  333. size: xml.lengthAttr(elem, "sz", LengthUsage.Border),
  334. offset: xml.lengthAttr(elem, "space", LengthUsage.Point),
  335. frame: xml.boolAttr(elem, 'frame'),
  336. shadow: xml.boolAttr(elem, 'shadow')
  337. };
  338. }
  339. function parseBorders (elem, xml) {
  340. var result = {};
  341. for (let e of xml.elements(elem)) {
  342. switch (e.localName) {
  343. case "left":
  344. result.left = parseBorder(e, xml);
  345. break;
  346. case "top":
  347. result.top = parseBorder(e, xml);
  348. break;
  349. case "right":
  350. result.right = parseBorder(e, xml);
  351. break;
  352. case "bottom":
  353. result.bottom = parseBorder(e, xml);
  354. break;
  355. }
  356. }
  357. return result;
  358. }
  359. var SectionType;
  360. (function (SectionType) {
  361. SectionType["Continuous"] = "continuous";
  362. SectionType["NextPage"] = "nextPage";
  363. SectionType["NextColumn"] = "nextColumn";
  364. SectionType["EvenPage"] = "evenPage";
  365. SectionType["OddPage"] = "oddPage";
  366. })(SectionType || (SectionType = {}));
  367. function parseSectionProperties (elem, xml = globalXmlParser) {
  368. var section = {};
  369. for (let e of xml.elements(elem)) {
  370. switch (e.localName) {
  371. case "pgSz":
  372. section.pageSize = {
  373. width: xml.lengthAttr(e, "w"),
  374. height: xml.lengthAttr(e, "h"),
  375. orientation: xml.attr(e, "orient")
  376. };
  377. break;
  378. case "type":
  379. section.type = xml.attr(e, "val");
  380. break;
  381. case "pgMar":
  382. section.pageMargins = {
  383. left: xml.lengthAttr(e, "left"),
  384. right: xml.lengthAttr(e, "right"),
  385. top: xml.lengthAttr(e, "top"),
  386. bottom: xml.lengthAttr(e, "bottom"),
  387. header: xml.lengthAttr(e, "header"),
  388. footer: xml.lengthAttr(e, "footer"),
  389. gutter: xml.lengthAttr(e, "gutter"),
  390. };
  391. break;
  392. case "cols":
  393. section.columns = parseColumns(e, xml);
  394. break;
  395. case "headerReference":
  396. (section.headerRefs ?? (section.headerRefs = [])).push(parseFooterHeaderReference(e, xml));
  397. break;
  398. case "footerReference":
  399. (section.footerRefs ?? (section.footerRefs = [])).push(parseFooterHeaderReference(e, xml));
  400. break;
  401. case "titlePg":
  402. section.titlePage = xml.boolAttr(e, "val", true);
  403. break;
  404. case "pgBorders":
  405. section.pageBorders = parseBorders(e, xml);
  406. break;
  407. case "pgNumType":
  408. section.pageNumber = parsePageNumber(e, xml);
  409. break;
  410. }
  411. }
  412. return section;
  413. }
  414. function parseColumns (elem, xml) {
  415. return {
  416. numberOfColumns: xml.intAttr(elem, "num"),
  417. space: xml.lengthAttr(elem, "space"),
  418. separator: xml.boolAttr(elem, "sep"),
  419. equalWidth: xml.boolAttr(elem, "equalWidth", true),
  420. columns: xml.elements(elem, "col")
  421. .map(e => ({
  422. width: xml.lengthAttr(e, "w"),
  423. space: xml.lengthAttr(e, "space")
  424. }))
  425. };
  426. }
  427. function parsePageNumber (elem, xml) {
  428. return {
  429. chapSep: xml.attr(elem, "chapSep"),
  430. chapStyle: xml.attr(elem, "chapStyle"),
  431. format: xml.attr(elem, "fmt"),
  432. start: xml.intAttr(elem, "start")
  433. };
  434. }
  435. function parseFooterHeaderReference (elem, xml) {
  436. return {
  437. id: xml.attr(elem, "id"),
  438. type: xml.attr(elem, "type"),
  439. };
  440. }
  441. function parseLineSpacing (elem, xml) {
  442. return {
  443. before: xml.lengthAttr(elem, "before"),
  444. after: xml.lengthAttr(elem, "after"),
  445. line: xml.intAttr(elem, "line"),
  446. lineRule: xml.attr(elem, "lineRule")
  447. };
  448. }
  449. function parseRunProperties (elem, xml) {
  450. let result = {};
  451. for (let el of xml.elements(elem)) {
  452. parseRunProperty(el, result, xml);
  453. }
  454. return result;
  455. }
  456. function parseRunProperty (elem, props, xml) {
  457. if (parseCommonProperty(elem, props, xml))
  458. return true;
  459. return false;
  460. }
  461. function parseParagraphProperties (elem, xml) {
  462. let result = {};
  463. for (let el of xml.elements(elem)) {
  464. parseParagraphProperty(el, result, xml);
  465. }
  466. return result;
  467. }
  468. function parseParagraphProperty (elem, props, xml) {
  469. if (elem.namespaceURI != ns$1.wordml)
  470. return false;
  471. if (parseCommonProperty(elem, props, xml))
  472. return true;
  473. switch (elem.localName) {
  474. case "tabs":
  475. props.tabs = parseTabs(elem, xml);
  476. break;
  477. case "sectPr":
  478. props.sectionProps = parseSectionProperties(elem, xml);
  479. break;
  480. case "numPr":
  481. props.numbering = parseNumbering$1(elem, xml);
  482. break;
  483. case "spacing":
  484. props.lineSpacing = parseLineSpacing(elem, xml);
  485. return false;
  486. case "textAlignment":
  487. props.textAlignment = xml.attr(elem, "val");
  488. return false;
  489. case "keepLines":
  490. props.keepLines = xml.boolAttr(elem, "val", true);
  491. break;
  492. case "keepNext":
  493. props.keepNext = xml.boolAttr(elem, "val", true);
  494. break;
  495. case "pageBreakBefore":
  496. props.pageBreakBefore = xml.boolAttr(elem, "val", true);
  497. break;
  498. case "outlineLvl":
  499. props.outlineLevel = xml.intAttr(elem, "val");
  500. break;
  501. case "pStyle":
  502. props.styleName = xml.attr(elem, "val");
  503. break;
  504. case "rPr":
  505. props.runProps = parseRunProperties(elem, xml);
  506. break;
  507. default:
  508. return false;
  509. }
  510. return true;
  511. }
  512. function parseTabs (elem, xml) {
  513. return xml.elements(elem, "tab")
  514. .map(e => ({
  515. position: xml.lengthAttr(e, "pos"),
  516. leader: xml.attr(e, "leader"),
  517. style: xml.attr(e, "val")
  518. }));
  519. }
  520. function parseNumbering$1 (elem, xml) {
  521. var result = {};
  522. for (let e of xml.elements(elem)) {
  523. switch (e.localName) {
  524. case "numId":
  525. result.id = xml.attr(e, "val");
  526. break;
  527. case "ilvl":
  528. result.level = xml.intAttr(e, "val");
  529. break;
  530. }
  531. }
  532. return result;
  533. }
  534. function parseNumberingPart (elem, xml) {
  535. let result = {
  536. numberings: [],
  537. abstractNumberings: [],
  538. bulletPictures: []
  539. };
  540. for (let e of xml.elements(elem)) {
  541. switch (e.localName) {
  542. case "num":
  543. result.numberings.push(parseNumbering(e, xml));
  544. break;
  545. case "abstractNum":
  546. result.abstractNumberings.push(parseAbstractNumbering(e, xml));
  547. break;
  548. case "numPicBullet":
  549. result.bulletPictures.push(parseNumberingBulletPicture(e, xml));
  550. break;
  551. }
  552. }
  553. return result;
  554. }
  555. function parseNumbering (elem, xml) {
  556. let result = {
  557. id: xml.attr(elem, 'numId'),
  558. overrides: []
  559. };
  560. for (let e of xml.elements(elem)) {
  561. switch (e.localName) {
  562. case "abstractNumId":
  563. result.abstractId = xml.attr(e, "val");
  564. break;
  565. case "lvlOverride":
  566. result.overrides.push(parseNumberingLevelOverrride(e, xml));
  567. break;
  568. }
  569. }
  570. return result;
  571. }
  572. function parseAbstractNumbering (elem, xml) {
  573. let result = {
  574. id: xml.attr(elem, 'abstractNumId'),
  575. levels: []
  576. };
  577. for (let e of xml.elements(elem)) {
  578. switch (e.localName) {
  579. case "name":
  580. result.name = xml.attr(e, "val");
  581. break;
  582. case "multiLevelType":
  583. result.multiLevelType = xml.attr(e, "val");
  584. break;
  585. case "numStyleLink":
  586. result.numberingStyleLink = xml.attr(e, "val");
  587. break;
  588. case "styleLink":
  589. result.styleLink = xml.attr(e, "val");
  590. break;
  591. case "lvl":
  592. result.levels.push(parseNumberingLevel(e, xml));
  593. break;
  594. }
  595. }
  596. return result;
  597. }
  598. function parseNumberingLevel (elem, xml) {
  599. let result = {
  600. level: xml.intAttr(elem, 'ilvl')
  601. };
  602. for (let e of xml.elements(elem)) {
  603. switch (e.localName) {
  604. case "start":
  605. result.start = xml.attr(e, "val");
  606. break;
  607. case "lvlRestart":
  608. result.restart = xml.intAttr(e, "val");
  609. break;
  610. case "numFmt":
  611. result.format = xml.attr(e, "val");
  612. break;
  613. case "lvlText":
  614. result.text = xml.attr(e, "val");
  615. break;
  616. case "lvlJc":
  617. result.justification = xml.attr(e, "val");
  618. break;
  619. case "lvlPicBulletId":
  620. result.bulletPictureId = xml.attr(e, "val");
  621. break;
  622. case "pStyle":
  623. result.paragraphStyle = xml.attr(e, "val");
  624. break;
  625. case "pPr":
  626. result.paragraphProps = parseParagraphProperties(e, xml);
  627. break;
  628. case "rPr":
  629. result.runProps = parseRunProperties(e, xml);
  630. break;
  631. }
  632. }
  633. return result;
  634. }
  635. function parseNumberingLevelOverrride (elem, xml) {
  636. let result = {
  637. level: xml.intAttr(elem, 'ilvl')
  638. };
  639. for (let e of xml.elements(elem)) {
  640. switch (e.localName) {
  641. case "startOverride":
  642. result.start = xml.intAttr(e, "val");
  643. break;
  644. case "lvl":
  645. result.numberingLevel = parseNumberingLevel(e, xml);
  646. break;
  647. }
  648. }
  649. return result;
  650. }
  651. function parseNumberingBulletPicture (elem, xml) {
  652. var pict = xml.element(elem, "pict");
  653. var shape = pict && xml.element(pict, "shape");
  654. var imagedata = shape && xml.element(shape, "imagedata");
  655. return imagedata ? {
  656. id: xml.attr(elem, "numPicBulletId"),
  657. referenceId: xml.attr(imagedata, "id"),
  658. style: xml.attr(shape, "style")
  659. } : null;
  660. }
  661. class NumberingPart extends Part {
  662. constructor(pkg, path, parser) {
  663. super(pkg, path);
  664. this._documentParser = parser;
  665. }
  666. parseXml (root) {
  667. Object.assign(this, parseNumberingPart(root, this._package.xmlParser));
  668. this.domNumberings = this._documentParser.parseNumberingFile(root);
  669. }
  670. }
  671. class StylesPart extends Part {
  672. constructor(pkg, path, parser) {
  673. super(pkg, path);
  674. this._documentParser = parser;
  675. }
  676. parseXml (root) {
  677. this.styles = this._documentParser.parseStylesFile(root);
  678. }
  679. }
  680. var DomType;
  681. (function (DomType) {
  682. DomType["Document"] = "document";
  683. DomType["Paragraph"] = "paragraph";
  684. DomType["Run"] = "run";
  685. DomType["Break"] = "break";
  686. DomType["NoBreakHyphen"] = "noBreakHyphen";
  687. DomType["Table"] = "table";
  688. DomType["Row"] = "row";
  689. DomType["Cell"] = "cell";
  690. DomType["Hyperlink"] = "hyperlink";
  691. DomType["SmartTag"] = "smartTag";
  692. DomType["Drawing"] = "drawing";
  693. DomType["Image"] = "image";
  694. DomType["Text"] = "text";
  695. DomType["Tab"] = "tab";
  696. DomType["Symbol"] = "symbol";
  697. DomType["BookmarkStart"] = "bookmarkStart";
  698. DomType["BookmarkEnd"] = "bookmarkEnd";
  699. DomType["Footer"] = "footer";
  700. DomType["Header"] = "header";
  701. DomType["FootnoteReference"] = "footnoteReference";
  702. DomType["EndnoteReference"] = "endnoteReference";
  703. DomType["Footnote"] = "footnote";
  704. DomType["Endnote"] = "endnote";
  705. DomType["SimpleField"] = "simpleField";
  706. DomType["ComplexField"] = "complexField";
  707. DomType["Instruction"] = "instruction";
  708. DomType["VmlPicture"] = "vmlPicture";
  709. DomType["MmlMath"] = "mmlMath";
  710. DomType["MmlMathParagraph"] = "mmlMathParagraph";
  711. DomType["MmlFraction"] = "mmlFraction";
  712. DomType["MmlFunction"] = "mmlFunction";
  713. DomType["MmlFunctionName"] = "mmlFunctionName";
  714. DomType["MmlNumerator"] = "mmlNumerator";
  715. DomType["MmlDenominator"] = "mmlDenominator";
  716. DomType["MmlRadical"] = "mmlRadical";
  717. DomType["MmlBase"] = "mmlBase";
  718. DomType["MmlDegree"] = "mmlDegree";
  719. DomType["MmlSuperscript"] = "mmlSuperscript";
  720. DomType["MmlSubscript"] = "mmlSubscript";
  721. DomType["MmlPreSubSuper"] = "mmlPreSubSuper";
  722. DomType["MmlSubArgument"] = "mmlSubArgument";
  723. DomType["MmlSuperArgument"] = "mmlSuperArgument";
  724. DomType["MmlNary"] = "mmlNary";
  725. DomType["MmlDelimiter"] = "mmlDelimiter";
  726. DomType["MmlRun"] = "mmlRun";
  727. DomType["MmlEquationArray"] = "mmlEquationArray";
  728. DomType["MmlLimit"] = "mmlLimit";
  729. DomType["MmlLimitLower"] = "mmlLimitLower";
  730. DomType["MmlMatrix"] = "mmlMatrix";
  731. DomType["MmlMatrixRow"] = "mmlMatrixRow";
  732. DomType["MmlBox"] = "mmlBox";
  733. DomType["MmlBar"] = "mmlBar";
  734. DomType["MmlGroupChar"] = "mmlGroupChar";
  735. DomType["VmlElement"] = "vmlElement";
  736. DomType["Inserted"] = "inserted";
  737. DomType["Deleted"] = "deleted";
  738. DomType["DeletedText"] = "deletedText";
  739. DomType["Comment"] = "comment";
  740. DomType["CommentReference"] = "commentReference";
  741. DomType["CommentRangeStart"] = "commentRangeStart";
  742. DomType["CommentRangeEnd"] = "commentRangeEnd";
  743. })(DomType || (DomType = {}));
  744. class OpenXmlElementBase {
  745. constructor() {
  746. this.children = [];
  747. this.cssStyle = {};
  748. }
  749. }
  750. class WmlHeader extends OpenXmlElementBase {
  751. constructor() {
  752. super(...arguments);
  753. this.type = DomType.Header;
  754. }
  755. }
  756. class WmlFooter extends OpenXmlElementBase {
  757. constructor() {
  758. super(...arguments);
  759. this.type = DomType.Footer;
  760. }
  761. }
  762. class BaseHeaderFooterPart extends Part {
  763. constructor(pkg, path, parser) {
  764. super(pkg, path);
  765. this._documentParser = parser;
  766. }
  767. parseXml (root) {
  768. this.rootElement = this.createRootElement();
  769. this.rootElement.children = this._documentParser.parseBodyElements(root);
  770. }
  771. }
  772. class HeaderPart extends BaseHeaderFooterPart {
  773. createRootElement () {
  774. return new WmlHeader();
  775. }
  776. }
  777. class FooterPart extends BaseHeaderFooterPart {
  778. createRootElement () {
  779. return new WmlFooter();
  780. }
  781. }
  782. function parseExtendedProps (root, xmlParser) {
  783. const result = {};
  784. for (let el of xmlParser.elements(root)) {
  785. switch (el.localName) {
  786. case "Template":
  787. result.template = el.textContent;
  788. break;
  789. case "Pages":
  790. result.pages = safeParseToInt(el.textContent);
  791. break;
  792. case "Words":
  793. result.words = safeParseToInt(el.textContent);
  794. break;
  795. case "Characters":
  796. result.characters = safeParseToInt(el.textContent);
  797. break;
  798. case "Application":
  799. result.application = el.textContent;
  800. break;
  801. case "Lines":
  802. result.lines = safeParseToInt(el.textContent);
  803. break;
  804. case "Paragraphs":
  805. result.paragraphs = safeParseToInt(el.textContent);
  806. break;
  807. case "Company":
  808. result.company = el.textContent;
  809. break;
  810. case "AppVersion":
  811. result.appVersion = el.textContent;
  812. break;
  813. }
  814. }
  815. return result;
  816. }
  817. function safeParseToInt (value) {
  818. if (typeof value === 'undefined')
  819. return;
  820. return parseInt(value);
  821. }
  822. class ExtendedPropsPart extends Part {
  823. parseXml (root) {
  824. this.props = parseExtendedProps(root, this._package.xmlParser);
  825. }
  826. }
  827. function parseCoreProps (root, xmlParser) {
  828. const result = {};
  829. for (let el of xmlParser.elements(root)) {
  830. switch (el.localName) {
  831. case "title":
  832. result.title = el.textContent;
  833. break;
  834. case "description":
  835. result.description = el.textContent;
  836. break;
  837. case "subject":
  838. result.subject = el.textContent;
  839. break;
  840. case "creator":
  841. result.creator = el.textContent;
  842. break;
  843. case "keywords":
  844. result.keywords = el.textContent;
  845. break;
  846. case "language":
  847. result.language = el.textContent;
  848. break;
  849. case "lastModifiedBy":
  850. result.lastModifiedBy = el.textContent;
  851. break;
  852. case "revision":
  853. el.textContent && (result.revision = parseInt(el.textContent));
  854. break;
  855. }
  856. }
  857. return result;
  858. }
  859. class CorePropsPart extends Part {
  860. parseXml (root) {
  861. this.props = parseCoreProps(root, this._package.xmlParser);
  862. }
  863. }
  864. class DmlTheme {
  865. }
  866. function parseTheme (elem, xml) {
  867. var result = new DmlTheme();
  868. var themeElements = xml.element(elem, "themeElements");
  869. for (let el of xml.elements(themeElements)) {
  870. switch (el.localName) {
  871. case "clrScheme":
  872. result.colorScheme = parseColorScheme(el, xml);
  873. break;
  874. case "fontScheme":
  875. result.fontScheme = parseFontScheme(el, xml);
  876. break;
  877. }
  878. }
  879. return result;
  880. }
  881. function parseColorScheme (elem, xml) {
  882. var result = {
  883. name: xml.attr(elem, "name"),
  884. colors: {}
  885. };
  886. for (let el of xml.elements(elem)) {
  887. var srgbClr = xml.element(el, "srgbClr");
  888. var sysClr = xml.element(el, "sysClr");
  889. if (srgbClr) {
  890. result.colors[el.localName] = xml.attr(srgbClr, "val");
  891. }
  892. else if (sysClr) {
  893. result.colors[el.localName] = xml.attr(sysClr, "lastClr");
  894. }
  895. }
  896. return result;
  897. }
  898. function parseFontScheme (elem, xml) {
  899. var result = {
  900. name: xml.attr(elem, "name"),
  901. };
  902. for (let el of xml.elements(elem)) {
  903. switch (el.localName) {
  904. case "majorFont":
  905. result.majorFont = parseFontInfo(el, xml);
  906. break;
  907. case "minorFont":
  908. result.minorFont = parseFontInfo(el, xml);
  909. break;
  910. }
  911. }
  912. return result;
  913. }
  914. function parseFontInfo (elem, xml) {
  915. return {
  916. latinTypeface: xml.elementAttr(elem, "latin", "typeface"),
  917. eaTypeface: xml.elementAttr(elem, "ea", "typeface"),
  918. csTypeface: xml.elementAttr(elem, "cs", "typeface"),
  919. };
  920. }
  921. class ThemePart extends Part {
  922. constructor(pkg, path) {
  923. super(pkg, path);
  924. }
  925. parseXml (root) {
  926. this.theme = parseTheme(root, this._package.xmlParser);
  927. }
  928. }
  929. class WmlBaseNote {
  930. }
  931. class WmlFootnote extends WmlBaseNote {
  932. constructor() {
  933. super(...arguments);
  934. this.type = DomType.Footnote;
  935. }
  936. }
  937. class WmlEndnote extends WmlBaseNote {
  938. constructor() {
  939. super(...arguments);
  940. this.type = DomType.Endnote;
  941. }
  942. }
  943. class BaseNotePart extends Part {
  944. constructor(pkg, path, parser) {
  945. super(pkg, path);
  946. this._documentParser = parser;
  947. }
  948. }
  949. class FootnotesPart extends BaseNotePart {
  950. constructor(pkg, path, parser) {
  951. super(pkg, path, parser);
  952. }
  953. parseXml (root) {
  954. this.notes = this._documentParser.parseNotes(root, "footnote", WmlFootnote);
  955. }
  956. }
  957. class EndnotesPart extends BaseNotePart {
  958. constructor(pkg, path, parser) {
  959. super(pkg, path, parser);
  960. }
  961. parseXml (root) {
  962. this.notes = this._documentParser.parseNotes(root, "endnote", WmlEndnote);
  963. }
  964. }
  965. function parseSettings (elem, xml) {
  966. var result = {};
  967. for (let el of xml.elements(elem)) {
  968. switch (el.localName) {
  969. case "defaultTabStop":
  970. result.defaultTabStop = xml.lengthAttr(el, "val");
  971. break;
  972. case "footnotePr":
  973. result.footnoteProps = parseNoteProperties(el, xml);
  974. break;
  975. case "endnotePr":
  976. result.endnoteProps = parseNoteProperties(el, xml);
  977. break;
  978. case "autoHyphenation":
  979. result.autoHyphenation = xml.boolAttr(el, "val");
  980. break;
  981. }
  982. }
  983. return result;
  984. }
  985. function parseNoteProperties (elem, xml) {
  986. var result = {
  987. defaultNoteIds: []
  988. };
  989. for (let el of xml.elements(elem)) {
  990. switch (el.localName) {
  991. case "numFmt":
  992. result.nummeringFormat = xml.attr(el, "val");
  993. break;
  994. case "footnote":
  995. case "endnote":
  996. result.defaultNoteIds.push(xml.attr(el, "id"));
  997. break;
  998. }
  999. }
  1000. return result;
  1001. }
  1002. class SettingsPart extends Part {
  1003. constructor(pkg, path) {
  1004. super(pkg, path);
  1005. }
  1006. parseXml (root) {
  1007. this.settings = parseSettings(root, this._package.xmlParser);
  1008. }
  1009. }
  1010. function parseCustomProps (root, xml) {
  1011. return xml.elements(root, "property").map(e => {
  1012. const firstChild = e.firstChild;
  1013. return {
  1014. formatId: xml.attr(e, "fmtid"),
  1015. name: xml.attr(e, "name"),
  1016. type: firstChild.nodeName,
  1017. value: firstChild.textContent
  1018. };
  1019. });
  1020. }
  1021. class CustomPropsPart extends Part {
  1022. parseXml (root) {
  1023. this.props = parseCustomProps(root, this._package.xmlParser);
  1024. }
  1025. }
  1026. class CommentsPart extends Part {
  1027. constructor(pkg, path, parser) {
  1028. super(pkg, path);
  1029. this._documentParser = parser;
  1030. }
  1031. parseXml (root) {
  1032. this.comments = this._documentParser.parseComments(root);
  1033. this.commentMap = keyBy(this.comments, x => x.id);
  1034. }
  1035. }
  1036. class CommentsExtendedPart extends Part {
  1037. constructor(pkg, path) {
  1038. super(pkg, path);
  1039. this.comments = [];
  1040. }
  1041. parseXml (root) {
  1042. const xml = this._package.xmlParser;
  1043. for (let el of xml.elements(root, "commentEx")) {
  1044. this.comments.push({
  1045. paraId: xml.attr(el, 'paraId'),
  1046. paraIdParent: xml.attr(el, 'paraIdParent'),
  1047. done: xml.boolAttr(el, 'done')
  1048. });
  1049. }
  1050. this.commentMap = keyBy(this.comments, x => x.paraId);
  1051. }
  1052. }
  1053. const topLevelRels = [
  1054. { type: RelationshipTypes.OfficeDocument, target: "word/document.xml" },
  1055. { type: RelationshipTypes.ExtendedProperties, target: "docProps/app.xml" },
  1056. { type: RelationshipTypes.CoreProperties, target: "docProps/core.xml" },
  1057. { type: RelationshipTypes.CustomProperties, target: "docProps/custom.xml" },
  1058. ];
  1059. class WordDocument {
  1060. constructor() {
  1061. this.parts = [];
  1062. this.partsMap = {};
  1063. }
  1064. static async load (blob, parser, options) {
  1065. var d = new WordDocument();
  1066. d._options = options;
  1067. d._parser = parser;
  1068. d._package = await OpenXmlPackage.load(blob, options);
  1069. d.rels = await d._package.loadRelationships();
  1070. await Promise.all(topLevelRels.map(rel => {
  1071. const r = d.rels.find(x => x.type === rel.type) ?? rel;
  1072. return d.loadRelationshipPart(r.target, r.type);
  1073. }));
  1074. return d;
  1075. }
  1076. save (type = "blob") {
  1077. return this._package.save(type);
  1078. }
  1079. async loadRelationshipPart (path, type) {
  1080. if (this.partsMap[path])
  1081. return this.partsMap[path];
  1082. if (!this._package.get(path))
  1083. return null;
  1084. let part = null;
  1085. switch (type) {
  1086. case RelationshipTypes.OfficeDocument:
  1087. this.documentPart = part = new DocumentPart(this._package, path, this._parser);
  1088. break;
  1089. case RelationshipTypes.FontTable:
  1090. this.fontTablePart = part = new FontTablePart(this._package, path);
  1091. break;
  1092. case RelationshipTypes.Numbering:
  1093. this.numberingPart = part = new NumberingPart(this._package, path, this._parser);
  1094. break;
  1095. case RelationshipTypes.Styles:
  1096. this.stylesPart = part = new StylesPart(this._package, path, this._parser);
  1097. break;
  1098. case RelationshipTypes.Theme:
  1099. this.themePart = part = new ThemePart(this._package, path);
  1100. break;
  1101. case RelationshipTypes.Footnotes:
  1102. this.footnotesPart = part = new FootnotesPart(this._package, path, this._parser);
  1103. break;
  1104. case RelationshipTypes.Endnotes:
  1105. this.endnotesPart = part = new EndnotesPart(this._package, path, this._parser);
  1106. break;
  1107. case RelationshipTypes.Footer:
  1108. part = new FooterPart(this._package, path, this._parser);
  1109. break;
  1110. case RelationshipTypes.Header:
  1111. part = new HeaderPart(this._package, path, this._parser);
  1112. break;
  1113. case RelationshipTypes.CoreProperties:
  1114. this.corePropsPart = part = new CorePropsPart(this._package, path);
  1115. break;
  1116. case RelationshipTypes.ExtendedProperties:
  1117. this.extendedPropsPart = part = new ExtendedPropsPart(this._package, path);
  1118. break;
  1119. case RelationshipTypes.CustomProperties:
  1120. part = new CustomPropsPart(this._package, path);
  1121. break;
  1122. case RelationshipTypes.Settings:
  1123. this.settingsPart = part = new SettingsPart(this._package, path);
  1124. break;
  1125. case RelationshipTypes.Comments:
  1126. this.commentsPart = part = new CommentsPart(this._package, path, this._parser);
  1127. break;
  1128. case RelationshipTypes.CommentsExtended:
  1129. this.commentsExtendedPart = part = new CommentsExtendedPart(this._package, path);
  1130. break;
  1131. }
  1132. if (part == null)
  1133. return Promise.resolve(null);
  1134. this.partsMap[path] = part;
  1135. this.parts.push(part);
  1136. await part.load();
  1137. if (part.rels?.length > 0) {
  1138. const [folder] = splitPath(part.path);
  1139. await Promise.all(part.rels.map(rel => this.loadRelationshipPart(resolvePath(rel.target, folder), rel.type)));
  1140. }
  1141. return part;
  1142. }
  1143. async loadDocumentImage (id, part) {
  1144. const x = await this.loadResource(part ?? this.documentPart, id, "blob");
  1145. return this.blobToURL(x);
  1146. }
  1147. async loadNumberingImage (id) {
  1148. const x = await this.loadResource(this.numberingPart, id, "blob");
  1149. return this.blobToURL(x);
  1150. }
  1151. async loadFont (id, key) {
  1152. const x = await this.loadResource(this.fontTablePart, id, "uint8array");
  1153. return x ? this.blobToURL(new Blob([deobfuscate(x, key)])) : x;
  1154. }
  1155. blobToURL (blob) {
  1156. if (!blob)
  1157. return null;
  1158. if (this._options.useBase64URL) {
  1159. return blobToBase64(blob);
  1160. }
  1161. return URL.createObjectURL(blob);
  1162. }
  1163. findPartByRelId (id, basePart = null) {
  1164. var rel = (basePart.rels ?? this.rels).find(r => r.id == id);
  1165. const folder = basePart ? splitPath(basePart.path)[0] : '';
  1166. return rel ? this.partsMap[resolvePath(rel.target, folder)] : null;
  1167. }
  1168. getPathById (part, id) {
  1169. const rel = part.rels.find(x => x.id == id);
  1170. const [folder] = splitPath(part.path);
  1171. return rel ? resolvePath(rel.target, folder) : null;
  1172. }
  1173. loadResource (part, id, outputType) {
  1174. const path = this.getPathById(part, id);
  1175. return path ? this._package.load(path, outputType) : Promise.resolve(null);
  1176. }
  1177. }
  1178. function deobfuscate (data, guidKey) {
  1179. const len = 16;
  1180. const trimmed = guidKey.replace(/{|}|-/g, "");
  1181. const numbers = new Array(len);
  1182. for (let i = 0; i < len; i++)
  1183. numbers[len - i - 1] = parseInt(trimmed.substr(i * 2, 2), 16);
  1184. for (let i = 0; i < 32; i++)
  1185. data[i] = data[i] ^ numbers[i % len];
  1186. return data;
  1187. }
  1188. function parseBookmarkStart (elem, xml) {
  1189. return {
  1190. type: DomType.BookmarkStart,
  1191. id: xml.attr(elem, "id"),
  1192. name: xml.attr(elem, "name"),
  1193. colFirst: xml.intAttr(elem, "colFirst"),
  1194. colLast: xml.intAttr(elem, "colLast")
  1195. };
  1196. }
  1197. function parseBookmarkEnd (elem, xml) {
  1198. return {
  1199. type: DomType.BookmarkEnd,
  1200. id: xml.attr(elem, "id")
  1201. };
  1202. }
  1203. class VmlElement extends OpenXmlElementBase {
  1204. constructor() {
  1205. super(...arguments);
  1206. this.type = DomType.VmlElement;
  1207. this.attrs = {};
  1208. }
  1209. }
  1210. function parseVmlElement (elem, parser) {
  1211. var result = new VmlElement();
  1212. switch (elem.localName) {
  1213. case "rect":
  1214. result.tagName = "rect";
  1215. Object.assign(result.attrs, { width: '100%', height: '100%' });
  1216. break;
  1217. case "oval":
  1218. result.tagName = "ellipse";
  1219. Object.assign(result.attrs, { cx: "50%", cy: "50%", rx: "50%", ry: "50%" });
  1220. break;
  1221. case "line":
  1222. result.tagName = "line";
  1223. break;
  1224. case "shape":
  1225. result.tagName = "g";
  1226. break;
  1227. case "textbox":
  1228. result.tagName = "foreignObject";
  1229. Object.assign(result.attrs, { width: '100%', height: '100%' });
  1230. break;
  1231. default:
  1232. return null;
  1233. }
  1234. for (const at of globalXmlParser.attrs(elem)) {
  1235. switch (at.localName) {
  1236. case "style":
  1237. result.cssStyleText = at.value;
  1238. break;
  1239. case "fillcolor":
  1240. result.attrs.fill = at.value;
  1241. break;
  1242. case "from":
  1243. const [x1, y1] = parsePoint(at.value);
  1244. Object.assign(result.attrs, { x1, y1 });
  1245. break;
  1246. case "to":
  1247. const [x2, y2] = parsePoint(at.value);
  1248. Object.assign(result.attrs, { x2, y2 });
  1249. break;
  1250. }
  1251. }
  1252. for (const el of globalXmlParser.elements(elem)) {
  1253. switch (el.localName) {
  1254. case "stroke":
  1255. Object.assign(result.attrs, parseStroke(el));
  1256. break;
  1257. case "fill":
  1258. Object.assign(result.attrs, parseFill());
  1259. break;
  1260. case "imagedata":
  1261. result.tagName = "image";
  1262. Object.assign(result.attrs, { width: '100%', height: '100%' });
  1263. result.imageHref = {
  1264. id: globalXmlParser.attr(el, "id"),
  1265. title: globalXmlParser.attr(el, "title"),
  1266. };
  1267. break;
  1268. case "txbxContent":
  1269. result.children.push(...parser.parseBodyElements(el));
  1270. break;
  1271. default:
  1272. const child = parseVmlElement(el, parser);
  1273. child && result.children.push(child);
  1274. break;
  1275. }
  1276. }
  1277. return result;
  1278. }
  1279. function parseStroke (el) {
  1280. return {
  1281. 'stroke': globalXmlParser.attr(el, "color"),
  1282. 'stroke-width': globalXmlParser.lengthAttr(el, "weight", LengthUsage.Emu) ?? '1px'
  1283. };
  1284. }
  1285. function parseFill (el) {
  1286. return {};
  1287. }
  1288. function parsePoint (val) {
  1289. return val.split(",");
  1290. }
  1291. class WmlComment extends OpenXmlElementBase {
  1292. constructor() {
  1293. super(...arguments);
  1294. this.type = DomType.Comment;
  1295. }
  1296. }
  1297. class WmlCommentReference extends OpenXmlElementBase {
  1298. constructor(id) {
  1299. super();
  1300. this.id = id;
  1301. this.type = DomType.CommentReference;
  1302. }
  1303. }
  1304. class WmlCommentRangeStart extends OpenXmlElementBase {
  1305. constructor(id) {
  1306. super();
  1307. this.id = id;
  1308. this.type = DomType.CommentRangeStart;
  1309. }
  1310. }
  1311. class WmlCommentRangeEnd extends OpenXmlElementBase {
  1312. constructor(id) {
  1313. super();
  1314. this.id = id;
  1315. this.type = DomType.CommentRangeEnd;
  1316. }
  1317. }
  1318. var autos = {
  1319. shd: "inherit",
  1320. color: "black",
  1321. borderColor: "black",
  1322. highlight: "transparent"
  1323. };
  1324. const supportedNamespaceURIs = [];
  1325. const mmlTagMap = {
  1326. "oMath": DomType.MmlMath,
  1327. "oMathPara": DomType.MmlMathParagraph,
  1328. "f": DomType.MmlFraction,
  1329. "func": DomType.MmlFunction,
  1330. "fName": DomType.MmlFunctionName,
  1331. "num": DomType.MmlNumerator,
  1332. "den": DomType.MmlDenominator,
  1333. "rad": DomType.MmlRadical,
  1334. "deg": DomType.MmlDegree,
  1335. "e": DomType.MmlBase,
  1336. "sSup": DomType.MmlSuperscript,
  1337. "sSub": DomType.MmlSubscript,
  1338. "sPre": DomType.MmlPreSubSuper,
  1339. "sup": DomType.MmlSuperArgument,
  1340. "sub": DomType.MmlSubArgument,
  1341. "d": DomType.MmlDelimiter,
  1342. "nary": DomType.MmlNary,
  1343. "eqArr": DomType.MmlEquationArray,
  1344. "lim": DomType.MmlLimit,
  1345. "limLow": DomType.MmlLimitLower,
  1346. "m": DomType.MmlMatrix,
  1347. "mr": DomType.MmlMatrixRow,
  1348. "box": DomType.MmlBox,
  1349. "bar": DomType.MmlBar,
  1350. "groupChr": DomType.MmlGroupChar
  1351. };
  1352. class DocumentParser {
  1353. constructor(options) {
  1354. this.options = {
  1355. ignoreWidth: false,
  1356. debug: false,
  1357. ...options
  1358. };
  1359. }
  1360. parseNotes (xmlDoc, elemName, elemClass) {
  1361. var result = [];
  1362. for (let el of globalXmlParser.elements(xmlDoc, elemName)) {
  1363. const node = new elemClass();
  1364. node.id = globalXmlParser.attr(el, "id");
  1365. node.noteType = globalXmlParser.attr(el, "type");
  1366. node.children = this.parseBodyElements(el);
  1367. result.push(node);
  1368. }
  1369. return result;
  1370. }
  1371. parseComments (xmlDoc) {
  1372. var result = [];
  1373. for (let el of globalXmlParser.elements(xmlDoc, "comment")) {
  1374. const item = new WmlComment();
  1375. item.id = globalXmlParser.attr(el, "id");
  1376. item.author = globalXmlParser.attr(el, "author");
  1377. item.initials = globalXmlParser.attr(el, "initials");
  1378. item.date = globalXmlParser.attr(el, "date");
  1379. item.children = this.parseBodyElements(el);
  1380. result.push(item);
  1381. }
  1382. return result;
  1383. }
  1384. parseDocumentFile (xmlDoc) {
  1385. var xbody = globalXmlParser.element(xmlDoc, "body");
  1386. var background = globalXmlParser.element(xmlDoc, "background");
  1387. var sectPr = globalXmlParser.element(xbody, "sectPr");
  1388. return {
  1389. type: DomType.Document,
  1390. children: this.parseBodyElements(xbody),
  1391. props: sectPr ? parseSectionProperties(sectPr, globalXmlParser) : {},
  1392. cssStyle: background ? this.parseBackground(background) : {},
  1393. };
  1394. }
  1395. parseBackground (elem) {
  1396. var result = {};
  1397. var color = xmlUtil.colorAttr(elem, "color");
  1398. if (color) {
  1399. result["background-color"] = color;
  1400. }
  1401. return result;
  1402. }
  1403. parseBodyElements (element) {
  1404. var children = [];
  1405. for (let elem of globalXmlParser.elements(element)) {
  1406. switch (elem.localName) {
  1407. case "p":
  1408. children.push(this.parseParagraph(elem));
  1409. break;
  1410. case "tbl":
  1411. children.push(this.parseTable(elem));
  1412. break;
  1413. case "sdt":
  1414. children.push(...this.parseSdt(elem, e => this.parseBodyElements(e)));
  1415. break;
  1416. }
  1417. }
  1418. return children;
  1419. }
  1420. parseStylesFile (xstyles) {
  1421. var result = [];
  1422. xmlUtil.foreach(xstyles, n => {
  1423. switch (n.localName) {
  1424. case "style":
  1425. result.push(this.parseStyle(n));
  1426. break;
  1427. case "docDefaults":
  1428. result.push(this.parseDefaultStyles(n));
  1429. break;
  1430. }
  1431. });
  1432. return result;
  1433. }
  1434. parseDefaultStyles (node) {
  1435. var result = {
  1436. id: null,
  1437. name: null,
  1438. target: null,
  1439. basedOn: null,
  1440. styles: []
  1441. };
  1442. xmlUtil.foreach(node, c => {
  1443. switch (c.localName) {
  1444. case "rPrDefault":
  1445. var rPr = globalXmlParser.element(c, "rPr");
  1446. if (rPr)
  1447. result.styles.push({
  1448. target: "span",
  1449. values: this.parseDefaultProperties(rPr, {})
  1450. });
  1451. break;
  1452. case "pPrDefault":
  1453. var pPr = globalXmlParser.element(c, "pPr");
  1454. if (pPr)
  1455. result.styles.push({
  1456. target: "p",
  1457. values: this.parseDefaultProperties(pPr, {})
  1458. });
  1459. break;
  1460. }
  1461. });
  1462. return result;
  1463. }
  1464. parseStyle (node) {
  1465. var result = {
  1466. id: globalXmlParser.attr(node, "styleId"),
  1467. isDefault: globalXmlParser.boolAttr(node, "default"),
  1468. name: null,
  1469. target: null,
  1470. basedOn: null,
  1471. styles: [],
  1472. linked: null
  1473. };
  1474. switch (globalXmlParser.attr(node, "type")) {
  1475. case "paragraph":
  1476. result.target = "p";
  1477. break;
  1478. case "table":
  1479. result.target = "table";
  1480. break;
  1481. case "character":
  1482. result.target = "span";
  1483. break;
  1484. }
  1485. xmlUtil.foreach(node, n => {
  1486. switch (n.localName) {
  1487. case "basedOn":
  1488. result.basedOn = globalXmlParser.attr(n, "val");
  1489. break;
  1490. case "name":
  1491. result.name = globalXmlParser.attr(n, "val");
  1492. break;
  1493. case "link":
  1494. result.linked = globalXmlParser.attr(n, "val");
  1495. break;
  1496. case "next":
  1497. result.next = globalXmlParser.attr(n, "val");
  1498. break;
  1499. case "aliases":
  1500. result.aliases = globalXmlParser.attr(n, "val").split(",");
  1501. break;
  1502. case "pPr":
  1503. result.styles.push({
  1504. target: "p",
  1505. values: this.parseDefaultProperties(n, {})
  1506. });
  1507. result.paragraphProps = parseParagraphProperties(n, globalXmlParser);
  1508. break;
  1509. case "rPr":
  1510. result.styles.push({
  1511. target: "span",
  1512. values: this.parseDefaultProperties(n, {})
  1513. });
  1514. result.runProps = parseRunProperties(n, globalXmlParser);
  1515. break;
  1516. case "tblPr":
  1517. case "tcPr":
  1518. result.styles.push({
  1519. target: "td",
  1520. values: this.parseDefaultProperties(n, {})
  1521. });
  1522. break;
  1523. case "tblStylePr":
  1524. for (let s of this.parseTableStyle(n))
  1525. result.styles.push(s);
  1526. break;
  1527. case "rsid":
  1528. case "qFormat":
  1529. case "hidden":
  1530. case "semiHidden":
  1531. case "unhideWhenUsed":
  1532. case "autoRedefine":
  1533. case "uiPriority":
  1534. break;
  1535. default:
  1536. this.options.debug && console.warn(`DOCX: Unknown style element: ${n.localName}`);
  1537. }
  1538. });
  1539. return result;
  1540. }
  1541. parseTableStyle (node) {
  1542. var result = [];
  1543. var type = globalXmlParser.attr(node, "type");
  1544. var selector = "";
  1545. var modificator = "";
  1546. switch (type) {
  1547. case "firstRow":
  1548. modificator = ".first-row";
  1549. selector = "tr.first-row td";
  1550. break;
  1551. case "lastRow":
  1552. modificator = ".last-row";
  1553. selector = "tr.last-row td";
  1554. break;
  1555. case "firstCol":
  1556. modificator = ".first-col";
  1557. selector = "td.first-col";
  1558. break;
  1559. case "lastCol":
  1560. modificator = ".last-col";
  1561. selector = "td.last-col";
  1562. break;
  1563. case "band1Vert":
  1564. modificator = ":not(.no-vband)";
  1565. selector = "td.odd-col";
  1566. break;
  1567. case "band2Vert":
  1568. modificator = ":not(.no-vband)";
  1569. selector = "td.even-col";
  1570. break;
  1571. case "band1Horz":
  1572. modificator = ":not(.no-hband)";
  1573. selector = "tr.odd-row";
  1574. break;
  1575. case "band2Horz":
  1576. modificator = ":not(.no-hband)";
  1577. selector = "tr.even-row";
  1578. break;
  1579. default: return [];
  1580. }
  1581. xmlUtil.foreach(node, n => {
  1582. switch (n.localName) {
  1583. case "pPr":
  1584. result.push({
  1585. target: `${selector} p`,
  1586. mod: modificator,
  1587. values: this.parseDefaultProperties(n, {})
  1588. });
  1589. break;
  1590. case "rPr":
  1591. result.push({
  1592. target: `${selector} span`,
  1593. mod: modificator,
  1594. values: this.parseDefaultProperties(n, {})
  1595. });
  1596. break;
  1597. case "tblPr":
  1598. case "tcPr":
  1599. result.push({
  1600. target: selector,
  1601. mod: modificator,
  1602. values: this.parseDefaultProperties(n, {})
  1603. });
  1604. break;
  1605. }
  1606. });
  1607. return result;
  1608. }
  1609. parseNumberingFile (xnums) {
  1610. var result = [];
  1611. var mapping = {};
  1612. var bullets = [];
  1613. xmlUtil.foreach(xnums, n => {
  1614. switch (n.localName) {
  1615. case "abstractNum":
  1616. this.parseAbstractNumbering(n, bullets)
  1617. .forEach(x => result.push(x));
  1618. break;
  1619. case "numPicBullet":
  1620. bullets.push(this.parseNumberingPicBullet(n));
  1621. break;
  1622. case "num":
  1623. var numId = globalXmlParser.attr(n, "numId");
  1624. var abstractNumId = globalXmlParser.elementAttr(n, "abstractNumId", "val");
  1625. mapping[abstractNumId] = numId;
  1626. break;
  1627. }
  1628. });
  1629. result.forEach(x => x.id = mapping[x.id]);
  1630. return result;
  1631. }
  1632. parseNumberingPicBullet (elem) {
  1633. var pict = globalXmlParser.element(elem, "pict");
  1634. var shape = pict && globalXmlParser.element(pict, "shape");
  1635. var imagedata = shape && globalXmlParser.element(shape, "imagedata");
  1636. return imagedata ? {
  1637. id: globalXmlParser.intAttr(elem, "numPicBulletId"),
  1638. src: globalXmlParser.attr(imagedata, "id"),
  1639. style: globalXmlParser.attr(shape, "style")
  1640. } : null;
  1641. }
  1642. parseAbstractNumbering (node, bullets) {
  1643. var result = [];
  1644. var id = globalXmlParser.attr(node, "abstractNumId");
  1645. xmlUtil.foreach(node, n => {
  1646. switch (n.localName) {
  1647. case "lvl":
  1648. result.push(this.parseNumberingLevel(id, n, bullets));
  1649. break;
  1650. }
  1651. });
  1652. return result;
  1653. }
  1654. parseNumberingLevel (id, node, bullets) {
  1655. var result = {
  1656. id: id,
  1657. level: globalXmlParser.intAttr(node, "ilvl"),
  1658. start: 1,
  1659. pStyleName: undefined,
  1660. pStyle: {},
  1661. rStyle: {},
  1662. suff: "tab"
  1663. };
  1664. xmlUtil.foreach(node, n => {
  1665. switch (n.localName) {
  1666. case "start":
  1667. result.start = globalXmlParser.intAttr(n, "val");
  1668. break;
  1669. case "pPr":
  1670. this.parseDefaultProperties(n, result.pStyle);
  1671. break;
  1672. case "rPr":
  1673. this.parseDefaultProperties(n, result.rStyle);
  1674. break;
  1675. case "lvlPicBulletId":
  1676. var id = globalXmlParser.intAttr(n, "val");
  1677. result.bullet = bullets.find(x => x?.id == id);
  1678. break;
  1679. case "lvlText":
  1680. result.levelText = globalXmlParser.attr(n, "val");
  1681. break;
  1682. case "pStyle":
  1683. result.pStyleName = globalXmlParser.attr(n, "val");
  1684. break;
  1685. case "numFmt":
  1686. result.format = globalXmlParser.attr(n, "val");
  1687. break;
  1688. case "suff":
  1689. result.suff = globalXmlParser.attr(n, "val");
  1690. break;
  1691. }
  1692. });
  1693. return result;
  1694. }
  1695. parseSdt (node, parser) {
  1696. const sdtContent = globalXmlParser.element(node, "sdtContent");
  1697. return sdtContent ? parser(sdtContent) : [];
  1698. }
  1699. parseInserted (node, parentParser) {
  1700. return {
  1701. type: DomType.Inserted,
  1702. children: parentParser(node)?.children ?? []
  1703. };
  1704. }
  1705. parseDeleted (node, parentParser) {
  1706. return {
  1707. type: DomType.Deleted,
  1708. children: parentParser(node)?.children ?? []
  1709. };
  1710. }
  1711. parseParagraph (node) {
  1712. var result = { type: DomType.Paragraph, children: [] };
  1713. for (let el of globalXmlParser.elements(node)) {
  1714. switch (el.localName) {
  1715. case "pPr":
  1716. this.parseParagraphProperties(el, result);
  1717. break;
  1718. case "r":
  1719. result.children.push(this.parseRun(el, result));
  1720. break;
  1721. case "hyperlink":
  1722. result.children.push(this.parseHyperlink(el, result));
  1723. break;
  1724. case "smartTag":
  1725. result.children.push(this.parseSmartTag(el, result));
  1726. break;
  1727. case "bookmarkStart":
  1728. result.children.push(parseBookmarkStart(el, globalXmlParser));
  1729. break;
  1730. case "bookmarkEnd":
  1731. result.children.push(parseBookmarkEnd(el, globalXmlParser));
  1732. break;
  1733. case "commentRangeStart":
  1734. result.children.push(new WmlCommentRangeStart(globalXmlParser.attr(el, "id")));
  1735. break;
  1736. case "commentRangeEnd":
  1737. result.children.push(new WmlCommentRangeEnd(globalXmlParser.attr(el, "id")));
  1738. break;
  1739. case "oMath":
  1740. case "oMathPara":
  1741. result.children.push(this.parseMathElement(el));
  1742. break;
  1743. case "sdt":
  1744. result.children.push(...this.parseSdt(el, e => this.parseParagraph(e).children));
  1745. break;
  1746. case "ins":
  1747. result.children.push(this.parseInserted(el, e => this.parseParagraph(e)));
  1748. break;
  1749. case "del":
  1750. result.children.push(this.parseDeleted(el, e => this.parseParagraph(e)));
  1751. break;
  1752. }
  1753. }
  1754. return result;
  1755. }
  1756. parseParagraphProperties (elem, paragraph) {
  1757. this.parseDefaultProperties(elem, paragraph.cssStyle = {}, null, c => {
  1758. if (parseParagraphProperty(c, paragraph, globalXmlParser))
  1759. return true;
  1760. switch (c.localName) {
  1761. case "pStyle":
  1762. paragraph.styleName = globalXmlParser.attr(c, "val");
  1763. break;
  1764. case "cnfStyle":
  1765. paragraph.className = values.classNameOfCnfStyle(c);
  1766. break;
  1767. case "framePr":
  1768. this.parseFrame(c, paragraph);
  1769. break;
  1770. case "rPr":
  1771. break;
  1772. default:
  1773. return false;
  1774. }
  1775. return true;
  1776. });
  1777. }
  1778. parseFrame (node, paragraph) {
  1779. var dropCap = globalXmlParser.attr(node, "dropCap");
  1780. if (dropCap == "drop")
  1781. paragraph.cssStyle["float"] = "left";
  1782. }
  1783. parseHyperlink (node, parent) {
  1784. var result = { type: DomType.Hyperlink, parent: parent, children: [] };
  1785. var anchor = globalXmlParser.attr(node, "anchor");
  1786. var relId = globalXmlParser.attr(node, "id");
  1787. if (anchor)
  1788. result.href = "#" + anchor;
  1789. if (relId)
  1790. result.id = relId;
  1791. xmlUtil.foreach(node, c => {
  1792. switch (c.localName) {
  1793. case "r":
  1794. result.children.push(this.parseRun(c, result));
  1795. break;
  1796. }
  1797. });
  1798. return result;
  1799. }
  1800. parseSmartTag (node, parent) {
  1801. var result = { type: DomType.SmartTag, parent, children: [] };
  1802. var uri = globalXmlParser.attr(node, "uri");
  1803. var element = globalXmlParser.attr(node, "element");
  1804. if (uri)
  1805. result.uri = uri;
  1806. if (element)
  1807. result.element = element;
  1808. xmlUtil.foreach(node, c => {
  1809. switch (c.localName) {
  1810. case "r":
  1811. result.children.push(this.parseRun(c, result));
  1812. break;
  1813. }
  1814. });
  1815. return result;
  1816. }
  1817. parseRun (node, parent) {
  1818. var result = { type: DomType.Run, parent: parent, children: [] };
  1819. xmlUtil.foreach(node, c => {
  1820. c = this.checkAlternateContent(c);
  1821. switch (c.localName) {
  1822. case "t":
  1823. result.children.push({
  1824. type: DomType.Text,
  1825. text: c.textContent
  1826. });
  1827. break;
  1828. case "delText":
  1829. result.children.push({
  1830. type: DomType.DeletedText,
  1831. text: c.textContent
  1832. });
  1833. break;
  1834. case "commentReference":
  1835. result.children.push(new WmlCommentReference(globalXmlParser.attr(c, "id")));
  1836. break;
  1837. case "fldSimple":
  1838. result.children.push({
  1839. type: DomType.SimpleField,
  1840. instruction: globalXmlParser.attr(c, "instr"),
  1841. lock: globalXmlParser.boolAttr(c, "lock", false),
  1842. dirty: globalXmlParser.boolAttr(c, "dirty", false)
  1843. });
  1844. break;
  1845. case "instrText":
  1846. result.fieldRun = true;
  1847. result.children.push({
  1848. type: DomType.Instruction,
  1849. text: c.textContent
  1850. });
  1851. break;
  1852. case "fldChar":
  1853. result.fieldRun = true;
  1854. result.children.push({
  1855. type: DomType.ComplexField,
  1856. charType: globalXmlParser.attr(c, "fldCharType"),
  1857. lock: globalXmlParser.boolAttr(c, "lock", false),
  1858. dirty: globalXmlParser.boolAttr(c, "dirty", false)
  1859. });
  1860. break;
  1861. case "noBreakHyphen":
  1862. result.children.push({ type: DomType.NoBreakHyphen });
  1863. break;
  1864. case "br":
  1865. result.children.push({
  1866. type: DomType.Break,
  1867. break: globalXmlParser.attr(c, "type") || "textWrapping"
  1868. });
  1869. break;
  1870. case "lastRenderedPageBreak":
  1871. result.children.push({
  1872. type: DomType.Break,
  1873. break: "lastRenderedPageBreak"
  1874. });
  1875. break;
  1876. case "sym":
  1877. result.children.push({
  1878. type: DomType.Symbol,
  1879. font: globalXmlParser.attr(c, "font"),
  1880. char: globalXmlParser.attr(c, "char")
  1881. });
  1882. break;
  1883. case "tab":
  1884. result.children.push({ type: DomType.Tab });
  1885. break;
  1886. case "footnoteReference":
  1887. result.children.push({
  1888. type: DomType.FootnoteReference,
  1889. id: globalXmlParser.attr(c, "id")
  1890. });
  1891. break;
  1892. case "endnoteReference":
  1893. result.children.push({
  1894. type: DomType.EndnoteReference,
  1895. id: globalXmlParser.attr(c, "id")
  1896. });
  1897. break;
  1898. case "drawing":
  1899. let d = this.parseDrawing(c);
  1900. if (d)
  1901. result.children = [d];
  1902. break;
  1903. case "pict":
  1904. result.children.push(this.parseVmlPicture(c));
  1905. break;
  1906. case "rPr":
  1907. this.parseRunProperties(c, result);
  1908. break;
  1909. }
  1910. });
  1911. return result;
  1912. }
  1913. parseMathElement (elem) {
  1914. const propsTag = `${elem.localName}Pr`;
  1915. const result = { type: mmlTagMap[elem.localName], children: [] };
  1916. for (const el of globalXmlParser.elements(elem)) {
  1917. const childType = mmlTagMap[el.localName];
  1918. if (childType) {
  1919. result.children.push(this.parseMathElement(el));
  1920. }
  1921. else if (el.localName == "r") {
  1922. var run = this.parseRun(el);
  1923. run.type = DomType.MmlRun;
  1924. result.children.push(run);
  1925. }
  1926. else if (el.localName == propsTag) {
  1927. result.props = this.parseMathProperies(el);
  1928. }
  1929. }
  1930. return result;
  1931. }
  1932. parseMathProperies (elem) {
  1933. const result = {};
  1934. for (const el of globalXmlParser.elements(elem)) {
  1935. switch (el.localName) {
  1936. case "chr":
  1937. result.char = globalXmlParser.attr(el, "val");
  1938. break;
  1939. case "vertJc":
  1940. result.verticalJustification = globalXmlParser.attr(el, "val");
  1941. break;
  1942. case "pos":
  1943. result.position = globalXmlParser.attr(el, "val");
  1944. break;
  1945. case "degHide":
  1946. result.hideDegree = globalXmlParser.boolAttr(el, "val");
  1947. break;
  1948. case "begChr":
  1949. result.beginChar = globalXmlParser.attr(el, "val");
  1950. break;
  1951. case "endChr":
  1952. result.endChar = globalXmlParser.attr(el, "val");
  1953. break;
  1954. }
  1955. }
  1956. return result;
  1957. }
  1958. parseRunProperties (elem, run) {
  1959. this.parseDefaultProperties(elem, run.cssStyle = {}, null, c => {
  1960. switch (c.localName) {
  1961. case "rStyle":
  1962. run.styleName = globalXmlParser.attr(c, "val");
  1963. break;
  1964. case "vertAlign":
  1965. run.verticalAlign = values.valueOfVertAlign(c, true);
  1966. break;
  1967. default:
  1968. return false;
  1969. }
  1970. return true;
  1971. });
  1972. }
  1973. parseVmlPicture (elem) {
  1974. const result = { type: DomType.VmlPicture, children: [] };
  1975. for (const el of globalXmlParser.elements(elem)) {
  1976. const child = parseVmlElement(el, this);
  1977. child && result.children.push(child);
  1978. }
  1979. return result;
  1980. }
  1981. checkAlternateContent (elem) {
  1982. if (elem.localName != 'AlternateContent')
  1983. return elem;
  1984. var choice = globalXmlParser.element(elem, "Choice");
  1985. if (choice) {
  1986. var requires = globalXmlParser.attr(choice, "Requires");
  1987. var namespaceURI = elem.lookupNamespaceURI(requires);
  1988. if (supportedNamespaceURIs.includes(namespaceURI))
  1989. return choice.firstElementChild;
  1990. }
  1991. return globalXmlParser.element(elem, "Fallback")?.firstElementChild;
  1992. }
  1993. parseDrawing (node) {
  1994. for (var n of globalXmlParser.elements(node)) {
  1995. switch (n.localName) {
  1996. case "inline":
  1997. case "anchor":
  1998. return this.parseDrawingWrapper(n);
  1999. }
  2000. }
  2001. }
  2002. parseDrawingWrapper (node) {
  2003. var result = { type: DomType.Drawing, children: [], cssStyle: {} };
  2004. var isAnchor = node.localName == "anchor";
  2005. let wrapType = null;
  2006. let simplePos = globalXmlParser.boolAttr(node, "simplePos");
  2007. globalXmlParser.boolAttr(node, "behindDoc");
  2008. let posX = { relative: "page", align: "left", offset: "0" };
  2009. let posY = { relative: "page", align: "top", offset: "0" };
  2010. for (var n of globalXmlParser.elements(node)) {
  2011. switch (n.localName) {
  2012. case "simplePos":
  2013. if (simplePos) {
  2014. posX.offset = globalXmlParser.lengthAttr(n, "x", LengthUsage.Emu);
  2015. posY.offset = globalXmlParser.lengthAttr(n, "y", LengthUsage.Emu);
  2016. }
  2017. break;
  2018. case "extent":
  2019. result.cssStyle["width"] = globalXmlParser.lengthAttr(n, "cx", LengthUsage.Emu);
  2020. result.cssStyle["height"] = globalXmlParser.lengthAttr(n, "cy", LengthUsage.Emu);
  2021. break;
  2022. case "positionH":
  2023. case "positionV":
  2024. if (!simplePos) {
  2025. let pos = n.localName == "positionH" ? posX : posY;
  2026. var alignNode = globalXmlParser.element(n, "align");
  2027. var offsetNode = globalXmlParser.element(n, "posOffset");
  2028. pos.relative = globalXmlParser.attr(n, "relativeFrom") ?? pos.relative;
  2029. if (alignNode)
  2030. pos.align = alignNode.textContent;
  2031. if (offsetNode)
  2032. pos.offset = xmlUtil.sizeValue(offsetNode, LengthUsage.Emu);
  2033. }
  2034. break;
  2035. case "wrapTopAndBottom":
  2036. wrapType = "wrapTopAndBottom";
  2037. break;
  2038. case "wrapNone":
  2039. wrapType = "wrapNone";
  2040. break;
  2041. case "graphic":
  2042. var g = this.parseGraphic(n);
  2043. if (g)
  2044. result.children.push(g);
  2045. break;
  2046. }
  2047. }
  2048. if (wrapType == "wrapTopAndBottom") {
  2049. result.cssStyle['display'] = 'block';
  2050. if (posX.align) {
  2051. result.cssStyle['text-align'] = posX.align;
  2052. result.cssStyle['width'] = "100%";
  2053. }
  2054. }
  2055. else if (wrapType == "wrapNone") {
  2056. result.cssStyle['display'] = 'block';
  2057. result.cssStyle['position'] = 'relative';
  2058. result.cssStyle["width"] = "0px";
  2059. result.cssStyle["height"] = "0px";
  2060. if (posX.offset)
  2061. result.cssStyle["left"] = posX.offset;
  2062. if (posY.offset)
  2063. result.cssStyle["top"] = posY.offset;
  2064. }
  2065. else if (isAnchor && (posX.align == 'left' || posX.align == 'right')) {
  2066. result.cssStyle["float"] = posX.align;
  2067. }
  2068. return result;
  2069. }
  2070. parseGraphic (elem) {
  2071. var graphicData = globalXmlParser.element(elem, "graphicData");
  2072. for (let n of globalXmlParser.elements(graphicData)) {
  2073. switch (n.localName) {
  2074. case "pic":
  2075. return this.parsePicture(n);
  2076. }
  2077. }
  2078. return null;
  2079. }
  2080. parsePicture (elem) {
  2081. var result = { type: DomType.Image, src: "", cssStyle: {} };
  2082. var blipFill = globalXmlParser.element(elem, "blipFill");
  2083. var blip = globalXmlParser.element(blipFill, "blip");
  2084. result.src = globalXmlParser.attr(blip, "embed");
  2085. var spPr = globalXmlParser.element(elem, "spPr");
  2086. var xfrm = globalXmlParser.element(spPr, "xfrm");
  2087. result.cssStyle["position"] = "relative";
  2088. for (var n of globalXmlParser.elements(xfrm)) {
  2089. switch (n.localName) {
  2090. case "ext":
  2091. result.cssStyle["width"] = globalXmlParser.lengthAttr(n, "cx", LengthUsage.Emu);
  2092. result.cssStyle["height"] = globalXmlParser.lengthAttr(n, "cy", LengthUsage.Emu);
  2093. break;
  2094. case "off":
  2095. result.cssStyle["left"] = globalXmlParser.lengthAttr(n, "x", LengthUsage.Emu);
  2096. result.cssStyle["top"] = globalXmlParser.lengthAttr(n, "y", LengthUsage.Emu);
  2097. break;
  2098. }
  2099. }
  2100. return result;
  2101. }
  2102. parseTable (node) {
  2103. var result = { type: DomType.Table, children: [] };
  2104. xmlUtil.foreach(node, c => {
  2105. switch (c.localName) {
  2106. case "tr":
  2107. result.children.push(this.parseTableRow(c));
  2108. break;
  2109. case "tblGrid":
  2110. result.columns = this.parseTableColumns(c);
  2111. break;
  2112. case "tblPr":
  2113. this.parseTableProperties(c, result);
  2114. break;
  2115. }
  2116. });
  2117. return result;
  2118. }
  2119. parseTableColumns (node) {
  2120. var result = [];
  2121. xmlUtil.foreach(node, n => {
  2122. switch (n.localName) {
  2123. case "gridCol":
  2124. result.push({ width: globalXmlParser.lengthAttr(n, "w") });
  2125. break;
  2126. }
  2127. });
  2128. return result;
  2129. }
  2130. parseTableProperties (elem, table) {
  2131. table.cssStyle = {};
  2132. table.cellStyle = {};
  2133. this.parseDefaultProperties(elem, table.cssStyle, table.cellStyle, c => {
  2134. switch (c.localName) {
  2135. case "tblStyle":
  2136. table.styleName = globalXmlParser.attr(c, "val");
  2137. break;
  2138. case "tblLook":
  2139. table.className = values.classNameOftblLook(c);
  2140. break;
  2141. case "tblpPr":
  2142. this.parseTablePosition(c, table);
  2143. break;
  2144. case "tblStyleColBandSize":
  2145. table.colBandSize = globalXmlParser.intAttr(c, "val");
  2146. break;
  2147. case "tblStyleRowBandSize":
  2148. table.rowBandSize = globalXmlParser.intAttr(c, "val");
  2149. break;
  2150. default:
  2151. return false;
  2152. }
  2153. return true;
  2154. });
  2155. switch (table.cssStyle["text-align"]) {
  2156. case "center":
  2157. delete table.cssStyle["text-align"];
  2158. table.cssStyle["margin-left"] = "auto";
  2159. table.cssStyle["margin-right"] = "auto";
  2160. break;
  2161. case "right":
  2162. delete table.cssStyle["text-align"];
  2163. table.cssStyle["margin-left"] = "auto";
  2164. break;
  2165. }
  2166. }
  2167. parseTablePosition (node, table) {
  2168. var topFromText = globalXmlParser.lengthAttr(node, "topFromText");
  2169. var bottomFromText = globalXmlParser.lengthAttr(node, "bottomFromText");
  2170. var rightFromText = globalXmlParser.lengthAttr(node, "rightFromText");
  2171. var leftFromText = globalXmlParser.lengthAttr(node, "leftFromText");
  2172. table.cssStyle["float"] = 'left';
  2173. table.cssStyle["margin-bottom"] = values.addSize(table.cssStyle["margin-bottom"], bottomFromText);
  2174. table.cssStyle["margin-left"] = values.addSize(table.cssStyle["margin-left"], leftFromText);
  2175. table.cssStyle["margin-right"] = values.addSize(table.cssStyle["margin-right"], rightFromText);
  2176. table.cssStyle["margin-top"] = values.addSize(table.cssStyle["margin-top"], topFromText);
  2177. }
  2178. parseTableRow (node) {
  2179. var result = { type: DomType.Row, children: [] };
  2180. xmlUtil.foreach(node, c => {
  2181. switch (c.localName) {
  2182. case "tc":
  2183. result.children.push(this.parseTableCell(c));
  2184. break;
  2185. case "trPr":
  2186. this.parseTableRowProperties(c, result);
  2187. break;
  2188. }
  2189. });
  2190. return result;
  2191. }
  2192. parseTableRowProperties (elem, row) {
  2193. row.cssStyle = this.parseDefaultProperties(elem, {}, null, c => {
  2194. switch (c.localName) {
  2195. case "cnfStyle":
  2196. row.className = values.classNameOfCnfStyle(c);
  2197. break;
  2198. case "tblHeader":
  2199. row.isHeader = globalXmlParser.boolAttr(c, "val");
  2200. break;
  2201. default:
  2202. return false;
  2203. }
  2204. return true;
  2205. });
  2206. }
  2207. parseTableCell (node) {
  2208. var result = { type: DomType.Cell, children: [] };
  2209. xmlUtil.foreach(node, c => {
  2210. switch (c.localName) {
  2211. case "tbl":
  2212. result.children.push(this.parseTable(c));
  2213. break;
  2214. case "p":
  2215. result.children.push(this.parseParagraph(c));
  2216. break;
  2217. case "tcPr":
  2218. this.parseTableCellProperties(c, result);
  2219. break;
  2220. }
  2221. });
  2222. return result;
  2223. }
  2224. parseTableCellProperties (elem, cell) {
  2225. cell.cssStyle = this.parseDefaultProperties(elem, {}, null, c => {
  2226. switch (c.localName) {
  2227. case "gridSpan":
  2228. cell.span = globalXmlParser.intAttr(c, "val", null);
  2229. break;
  2230. case "vMerge":
  2231. cell.verticalMerge = globalXmlParser.attr(c, "val") ?? "continue";
  2232. break;
  2233. case "cnfStyle":
  2234. cell.className = values.classNameOfCnfStyle(c);
  2235. break;
  2236. default:
  2237. return false;
  2238. }
  2239. return true;
  2240. });
  2241. }
  2242. parseDefaultProperties (elem, style = null, childStyle = null, handler = null) {
  2243. style = style || {};
  2244. xmlUtil.foreach(elem, c => {
  2245. if (handler?.(c))
  2246. return;
  2247. switch (c.localName) {
  2248. case "jc":
  2249. style["text-align"] = values.valueOfJc(c);
  2250. break;
  2251. case "textAlignment":
  2252. style["vertical-align"] = values.valueOfTextAlignment(c);
  2253. break;
  2254. case "color":
  2255. style["color"] = xmlUtil.colorAttr(c, "val", null, autos.color);
  2256. break;
  2257. case "sz":
  2258. style["font-size"] = style["min-height"] = globalXmlParser.lengthAttr(c, "val", LengthUsage.FontSize);
  2259. break;
  2260. case "shd":
  2261. style["background-color"] = xmlUtil.colorAttr(c, "fill", null, autos.shd);
  2262. break;
  2263. case "highlight":
  2264. style["background-color"] = xmlUtil.colorAttr(c, "val", null, autos.highlight);
  2265. break;
  2266. case "vertAlign":
  2267. break;
  2268. case "position":
  2269. style.verticalAlign = globalXmlParser.lengthAttr(c, "val", LengthUsage.FontSize);
  2270. break;
  2271. case "tcW":
  2272. if (this.options.ignoreWidth)
  2273. break;
  2274. case "tblW":
  2275. style["width"] = values.valueOfSize(c, "w");
  2276. break;
  2277. case "trHeight":
  2278. this.parseTrHeight(c, style);
  2279. break;
  2280. case "strike":
  2281. style["text-decoration"] = globalXmlParser.boolAttr(c, "val", true) ? "line-through" : "none";
  2282. break;
  2283. case "b":
  2284. style["font-weight"] = globalXmlParser.boolAttr(c, "val", true) ? "bold" : "normal";
  2285. break;
  2286. case "i":
  2287. style["font-style"] = globalXmlParser.boolAttr(c, "val", true) ? "italic" : "normal";
  2288. break;
  2289. case "caps":
  2290. style["text-transform"] = globalXmlParser.boolAttr(c, "val", true) ? "uppercase" : "none";
  2291. break;
  2292. case "smallCaps":
  2293. style["font-variant"] = globalXmlParser.boolAttr(c, "val", true) ? "small-caps" : "none";
  2294. break;
  2295. case "u":
  2296. this.parseUnderline(c, style);
  2297. break;
  2298. case "ind":
  2299. case "tblInd":
  2300. this.parseIndentation(c, style);
  2301. break;
  2302. case "rFonts":
  2303. this.parseFont(c, style);
  2304. break;
  2305. case "tblBorders":
  2306. this.parseBorderProperties(c, childStyle || style);
  2307. break;
  2308. case "tblCellSpacing":
  2309. style["border-spacing"] = values.valueOfMargin(c);
  2310. style["border-collapse"] = "separate";
  2311. break;
  2312. case "pBdr":
  2313. this.parseBorderProperties(c, style);
  2314. break;
  2315. case "bdr":
  2316. style["border"] = values.valueOfBorder(c);
  2317. break;
  2318. case "tcBorders":
  2319. this.parseBorderProperties(c, style);
  2320. break;
  2321. case "vanish":
  2322. if (globalXmlParser.boolAttr(c, "val", true))
  2323. style["display"] = "none";
  2324. break;
  2325. case "kern":
  2326. break;
  2327. case "noWrap":
  2328. break;
  2329. case "tblCellMar":
  2330. case "tcMar":
  2331. this.parseMarginProperties(c, childStyle || style);
  2332. break;
  2333. case "tblLayout":
  2334. style["table-layout"] = values.valueOfTblLayout(c);
  2335. break;
  2336. case "vAlign":
  2337. style["vertical-align"] = values.valueOfTextAlignment(c);
  2338. break;
  2339. case "spacing":
  2340. if (elem.localName == "pPr")
  2341. this.parseSpacing(c, style);
  2342. break;
  2343. case "wordWrap":
  2344. if (globalXmlParser.boolAttr(c, "val"))
  2345. style["overflow-wrap"] = "break-word";
  2346. break;
  2347. case "suppressAutoHyphens":
  2348. style["hyphens"] = globalXmlParser.boolAttr(c, "val", true) ? "none" : "auto";
  2349. break;
  2350. case "lang":
  2351. style["$lang"] = globalXmlParser.attr(c, "val");
  2352. break;
  2353. case "bCs":
  2354. case "iCs":
  2355. case "szCs":
  2356. case "tabs":
  2357. case "outlineLvl":
  2358. case "contextualSpacing":
  2359. case "tblStyleColBandSize":
  2360. case "tblStyleRowBandSize":
  2361. case "webHidden":
  2362. case "pageBreakBefore":
  2363. case "suppressLineNumbers":
  2364. case "keepLines":
  2365. case "keepNext":
  2366. case "widowControl":
  2367. case "bidi":
  2368. case "rtl":
  2369. case "noProof":
  2370. break;
  2371. default:
  2372. if (this.options.debug)
  2373. console.warn(`DOCX: Unknown document element: ${elem.localName}.${c.localName}`);
  2374. break;
  2375. }
  2376. });
  2377. return style;
  2378. }
  2379. parseUnderline (node, style) {
  2380. var val = globalXmlParser.attr(node, "val");
  2381. if (val == null)
  2382. return;
  2383. switch (val) {
  2384. case "dash":
  2385. case "dashDotDotHeavy":
  2386. case "dashDotHeavy":
  2387. case "dashedHeavy":
  2388. case "dashLong":
  2389. case "dashLongHeavy":
  2390. case "dotDash":
  2391. case "dotDotDash":
  2392. style["text-decoration"] = "underline dashed";
  2393. break;
  2394. case "dotted":
  2395. case "dottedHeavy":
  2396. style["text-decoration"] = "underline dotted";
  2397. break;
  2398. case "double":
  2399. style["text-decoration"] = "underline double";
  2400. break;
  2401. case "single":
  2402. case "thick":
  2403. style["text-decoration"] = "underline";
  2404. break;
  2405. case "wave":
  2406. case "wavyDouble":
  2407. case "wavyHeavy":
  2408. style["text-decoration"] = "underline wavy";
  2409. break;
  2410. case "words":
  2411. style["text-decoration"] = "underline";
  2412. break;
  2413. case "none":
  2414. style["text-decoration"] = "none";
  2415. break;
  2416. }
  2417. var col = xmlUtil.colorAttr(node, "color");
  2418. if (col)
  2419. style["text-decoration-color"] = col;
  2420. }
  2421. parseFont (node, style) {
  2422. var ascii = globalXmlParser.attr(node, "ascii");
  2423. var asciiTheme = values.themeValue(node, "asciiTheme");
  2424. var fonts = [ascii, asciiTheme].filter(x => x).join(', ');
  2425. if (fonts.length > 0)
  2426. style["font-family"] = fonts;
  2427. }
  2428. parseIndentation (node, style) {
  2429. var firstLine = globalXmlParser.lengthAttr(node, "firstLine");
  2430. var hanging = globalXmlParser.lengthAttr(node, "hanging");
  2431. var left = globalXmlParser.lengthAttr(node, "left");
  2432. var start = globalXmlParser.lengthAttr(node, "start");
  2433. var right = globalXmlParser.lengthAttr(node, "right");
  2434. var end = globalXmlParser.lengthAttr(node, "end");
  2435. if (firstLine)
  2436. style["text-indent"] = firstLine;
  2437. if (hanging)
  2438. style["text-indent"] = `-${hanging}`;
  2439. if (left || start)
  2440. style["margin-left"] = left || start;
  2441. if (right || end)
  2442. style["margin-right"] = right || end;
  2443. }
  2444. parseSpacing (node, style) {
  2445. var before = globalXmlParser.lengthAttr(node, "before");
  2446. var after = globalXmlParser.lengthAttr(node, "after");
  2447. var line = globalXmlParser.intAttr(node, "line", null);
  2448. var lineRule = globalXmlParser.attr(node, "lineRule");
  2449. if (before)
  2450. style["margin-top"] = before;
  2451. if (after)
  2452. style["margin-bottom"] = after;
  2453. if (line !== null) {
  2454. switch (lineRule) {
  2455. case "auto":
  2456. style["line-height"] = `${(line / 240).toFixed(2)}`;
  2457. break;
  2458. case "atLeast":
  2459. style["line-height"] = `calc(100% + ${line / 20}pt)`;
  2460. break;
  2461. default:
  2462. style["line-height"] = style["min-height"] = `${line / 20}pt`;
  2463. break;
  2464. }
  2465. }
  2466. }
  2467. parseMarginProperties (node, output) {
  2468. xmlUtil.foreach(node, c => {
  2469. switch (c.localName) {
  2470. case "left":
  2471. output["padding-left"] = values.valueOfMargin(c);
  2472. break;
  2473. case "right":
  2474. output["padding-right"] = values.valueOfMargin(c);
  2475. break;
  2476. case "top":
  2477. output["padding-top"] = values.valueOfMargin(c);
  2478. break;
  2479. case "bottom":
  2480. output["padding-bottom"] = values.valueOfMargin(c);
  2481. break;
  2482. }
  2483. });
  2484. }
  2485. parseTrHeight (node, output) {
  2486. switch (globalXmlParser.attr(node, "hRule")) {
  2487. case "exact":
  2488. output["height"] = globalXmlParser.lengthAttr(node, "val");
  2489. break;
  2490. case "atLeast":
  2491. default:
  2492. output["height"] = globalXmlParser.lengthAttr(node, "val");
  2493. break;
  2494. }
  2495. }
  2496. parseBorderProperties (node, output) {
  2497. xmlUtil.foreach(node, c => {
  2498. switch (c.localName) {
  2499. case "start":
  2500. case "left":
  2501. output["border-left"] = values.valueOfBorder(c);
  2502. break;
  2503. case "end":
  2504. case "right":
  2505. output["border-right"] = values.valueOfBorder(c);
  2506. break;
  2507. case "top":
  2508. output["border-top"] = values.valueOfBorder(c);
  2509. break;
  2510. case "bottom":
  2511. output["border-bottom"] = values.valueOfBorder(c);
  2512. break;
  2513. }
  2514. });
  2515. }
  2516. }
  2517. const knownColors = ['black', 'blue', 'cyan', 'darkBlue', 'darkCyan', 'darkGray', 'darkGreen', 'darkMagenta', 'darkRed', 'darkYellow', 'green', 'lightGray', 'magenta', 'none', 'red', 'white', 'yellow'];
  2518. class xmlUtil {
  2519. static foreach (node, cb) {
  2520. for (var i = 0; i < node.childNodes.length; i++) {
  2521. let n = node.childNodes[i];
  2522. if (n.nodeType == Node.ELEMENT_NODE)
  2523. cb(n);
  2524. }
  2525. }
  2526. static colorAttr (node, attrName, defValue = null, autoColor = 'black') {
  2527. var v = globalXmlParser.attr(node, attrName);
  2528. if (v) {
  2529. if (v == "auto") {
  2530. return autoColor;
  2531. }
  2532. else if (knownColors.includes(v)) {
  2533. return v;
  2534. }
  2535. return `#${v}`;
  2536. }
  2537. var themeColor = globalXmlParser.attr(node, "themeColor");
  2538. return themeColor ? `var(--docx-${themeColor}-color)` : defValue;
  2539. }
  2540. static sizeValue (node, type = LengthUsage.Dxa) {
  2541. return convertLength(node.textContent, type);
  2542. }
  2543. }
  2544. class values {
  2545. static themeValue (c, attr) {
  2546. var val = globalXmlParser.attr(c, attr);
  2547. return val ? `var(--docx-${val}-font)` : null;
  2548. }
  2549. static valueOfSize (c, attr) {
  2550. var type = LengthUsage.Dxa;
  2551. switch (globalXmlParser.attr(c, "type")) {
  2552. case "dxa": break;
  2553. case "pct":
  2554. type = LengthUsage.Percent;
  2555. break;
  2556. case "auto": return "auto";
  2557. }
  2558. return globalXmlParser.lengthAttr(c, attr, type);
  2559. }
  2560. static valueOfMargin (c) {
  2561. return globalXmlParser.lengthAttr(c, "w");
  2562. }
  2563. static valueOfBorder (c) {
  2564. var type = globalXmlParser.attr(c, "val");
  2565. if (type == "nil")
  2566. return "none";
  2567. var color = xmlUtil.colorAttr(c, "color");
  2568. var size = globalXmlParser.lengthAttr(c, "sz", LengthUsage.Border);
  2569. return `${size} solid ${color == "auto" ? autos.borderColor : color}`;
  2570. }
  2571. static valueOfTblLayout (c) {
  2572. var type = globalXmlParser.attr(c, "val");
  2573. return type == "fixed" ? "fixed" : "auto";
  2574. }
  2575. static classNameOfCnfStyle (c) {
  2576. const val = globalXmlParser.attr(c, "val");
  2577. const classes = [
  2578. 'first-row', 'last-row', 'first-col', 'last-col',
  2579. 'odd-col', 'even-col', 'odd-row', 'even-row',
  2580. 'ne-cell', 'nw-cell', 'se-cell', 'sw-cell'
  2581. ];
  2582. return classes.filter((_, i) => val[i] == '1').join(' ');
  2583. }
  2584. static valueOfJc (c) {
  2585. var type = globalXmlParser.attr(c, "val");
  2586. switch (type) {
  2587. case "start":
  2588. case "left": return "left";
  2589. case "center": return "center";
  2590. case "end":
  2591. case "right": return "right";
  2592. case "both": return "justify";
  2593. }
  2594. return type;
  2595. }
  2596. static valueOfVertAlign (c, asTagName = false) {
  2597. var type = globalXmlParser.attr(c, "val");
  2598. switch (type) {
  2599. case "subscript": return "sub";
  2600. case "superscript": return asTagName ? "sup" : "super";
  2601. }
  2602. return asTagName ? null : type;
  2603. }
  2604. static valueOfTextAlignment (c) {
  2605. var type = globalXmlParser.attr(c, "val");
  2606. switch (type) {
  2607. case "auto":
  2608. case "baseline": return "baseline";
  2609. case "top": return "top";
  2610. case "center": return "middle";
  2611. case "bottom": return "bottom";
  2612. }
  2613. return type;
  2614. }
  2615. static addSize (a, b) {
  2616. if (a == null)
  2617. return b;
  2618. if (b == null)
  2619. return a;
  2620. return `calc(${a} + ${b})`;
  2621. }
  2622. static classNameOftblLook (c) {
  2623. const val = globalXmlParser.hexAttr(c, "val", 0);
  2624. let className = "";
  2625. if (globalXmlParser.boolAttr(c, "firstRow") || (val & 0x0020))
  2626. className += " first-row";
  2627. if (globalXmlParser.boolAttr(c, "lastRow") || (val & 0x0040))
  2628. className += " last-row";
  2629. if (globalXmlParser.boolAttr(c, "firstColumn") || (val & 0x0080))
  2630. className += " first-col";
  2631. if (globalXmlParser.boolAttr(c, "lastColumn") || (val & 0x0100))
  2632. className += " last-col";
  2633. if (globalXmlParser.boolAttr(c, "noHBand") || (val & 0x0200))
  2634. className += " no-hband";
  2635. if (globalXmlParser.boolAttr(c, "noVBand") || (val & 0x0400))
  2636. className += " no-vband";
  2637. return className.trim();
  2638. }
  2639. }
  2640. const defaultTab = { pos: 0, leader: "none", style: "left" };
  2641. const maxTabs = 50;
  2642. function computePixelToPoint (container = document.body) {
  2643. const temp = document.createElement("div");
  2644. temp.style.width = '100pt';
  2645. container.appendChild(temp);
  2646. const result = 100 / temp.offsetWidth;
  2647. container.removeChild(temp);
  2648. return result;
  2649. }
  2650. function updateTabStop (elem, tabs, defaultTabSize, pixelToPoint = 72 / 96) {
  2651. const p = elem.closest("p");
  2652. const ebb = elem.getBoundingClientRect();
  2653. const pbb = p.getBoundingClientRect();
  2654. const pcs = getComputedStyle(p);
  2655. const tabStops = tabs?.length > 0 ? tabs.map(t => ({
  2656. pos: lengthToPoint(t.position),
  2657. leader: t.leader,
  2658. style: t.style
  2659. })).sort((a, b) => a.pos - b.pos) : [defaultTab];
  2660. const lastTab = tabStops[tabStops.length - 1];
  2661. const pWidthPt = pbb.width * pixelToPoint;
  2662. const size = lengthToPoint(defaultTabSize);
  2663. let pos = lastTab.pos + size;
  2664. if (pos < pWidthPt) {
  2665. for (; pos < pWidthPt && tabStops.length < maxTabs; pos += size) {
  2666. tabStops.push({ ...defaultTab, pos: pos });
  2667. }
  2668. }
  2669. const marginLeft = parseFloat(pcs.marginLeft);
  2670. const pOffset = pbb.left + marginLeft;
  2671. const left = (ebb.left - pOffset) * pixelToPoint;
  2672. const tab = tabStops.find(t => t.style != "clear" && t.pos > left);
  2673. if (tab == null)
  2674. return;
  2675. let width = 1;
  2676. if (tab.style == "right" || tab.style == "center") {
  2677. const tabStops = Array.from(p.querySelectorAll(`.${elem.className}`));
  2678. const nextIdx = tabStops.indexOf(elem) + 1;
  2679. const range = document.createRange();
  2680. range.setStart(elem, 1);
  2681. if (nextIdx < tabStops.length) {
  2682. range.setEndBefore(tabStops[nextIdx]);
  2683. }
  2684. else {
  2685. range.setEndAfter(p);
  2686. }
  2687. const mul = tab.style == "center" ? 0.5 : 1;
  2688. const nextBB = range.getBoundingClientRect();
  2689. const offset = nextBB.left + mul * nextBB.width - (pbb.left - marginLeft);
  2690. width = tab.pos - offset * pixelToPoint;
  2691. }
  2692. else {
  2693. width = tab.pos - left;
  2694. }
  2695. elem.innerHTML = "&nbsp;";
  2696. elem.style.textDecoration = "inherit";
  2697. elem.style.wordSpacing = `${width.toFixed(0)}pt`;
  2698. switch (tab.leader) {
  2699. case "dot":
  2700. case "middleDot":
  2701. elem.style.textDecoration = "underline";
  2702. elem.style.textDecorationStyle = "dotted";
  2703. break;
  2704. case "hyphen":
  2705. case "heavy":
  2706. case "underscore":
  2707. elem.style.textDecoration = "underline";
  2708. break;
  2709. }
  2710. }
  2711. function lengthToPoint (length) {
  2712. return parseFloat(length);
  2713. }
  2714. const ns = {
  2715. svg: "http://www.w3.org/2000/svg",
  2716. mathML: "http://www.w3.org/1998/Math/MathML"
  2717. };
  2718. class HtmlRenderer {
  2719. constructor(htmlDocument) {
  2720. this.htmlDocument = htmlDocument;
  2721. this.className = "docx";
  2722. this.styleMap = {};
  2723. this.currentPart = null;
  2724. this.tableVerticalMerges = [];
  2725. this.currentVerticalMerge = null;
  2726. this.tableCellPositions = [];
  2727. this.currentCellPosition = null;
  2728. this.footnoteMap = {};
  2729. this.endnoteMap = {};
  2730. this.currentEndnoteIds = [];
  2731. this.usedHederFooterParts = [];
  2732. this.currentTabs = [];
  2733. this.tabsTimeout = 0;
  2734. this.commentMap = {};
  2735. this.tasks = [];
  2736. this.postRenderTasks = [];
  2737. this.createElement = createElement;
  2738. }
  2739. render (document, bodyContainer, styleContainer = null, options) {
  2740. this.document = document;
  2741. this.options = options;
  2742. this.className = options.className;
  2743. this.rootSelector = options.inWrapper ? `.${this.className}-wrapper` : ':root';
  2744. this.styleMap = null;
  2745. this.tasks = [];
  2746. if (this.options.renderComments && globalThis.Highlight) {
  2747. this.commentHighlight = new Highlight();
  2748. }
  2749. styleContainer = styleContainer || bodyContainer;
  2750. removeAllElements(styleContainer);
  2751. removeAllElements(bodyContainer);
  2752. appendComment(styleContainer, "docxjs library predefined styles");
  2753. styleContainer.appendChild(this.renderDefaultStyle());
  2754. if (document.themePart) {
  2755. appendComment(styleContainer, "docxjs document theme values");
  2756. this.renderTheme(document.themePart, styleContainer);
  2757. }
  2758. if (document.stylesPart != null) {
  2759. this.styleMap = this.processStyles(document.stylesPart.styles);
  2760. appendComment(styleContainer, "docxjs document styles");
  2761. styleContainer.appendChild(this.renderStyles(document.stylesPart.styles));
  2762. }
  2763. if (document.numberingPart) {
  2764. this.prodessNumberings(document.numberingPart.domNumberings);
  2765. appendComment(styleContainer, "docxjs document numbering styles");
  2766. styleContainer.appendChild(this.renderNumbering(document.numberingPart.domNumberings, styleContainer));
  2767. }
  2768. if (document.footnotesPart) {
  2769. this.footnoteMap = keyBy(document.footnotesPart.notes, x => x.id);
  2770. }
  2771. if (document.endnotesPart) {
  2772. this.endnoteMap = keyBy(document.endnotesPart.notes, x => x.id);
  2773. }
  2774. if (document.settingsPart) {
  2775. this.defaultTabSize = document.settingsPart.settings?.defaultTabStop;
  2776. }
  2777. if (!options.ignoreFonts && document.fontTablePart)
  2778. this.renderFontTable(document.fontTablePart, styleContainer);
  2779. var sectionElements = this.renderSections(document.documentPart.body);
  2780. if (this.options.inWrapper) {
  2781. bodyContainer.appendChild(this.renderWrapper(sectionElements));
  2782. }
  2783. else {
  2784. appendChildren(bodyContainer, sectionElements);
  2785. }
  2786. if (this.commentHighlight && options.renderComments) {
  2787. CSS.highlights.set(`${this.className}-comments`, this.commentHighlight);
  2788. }
  2789. this.refreshTabStops();
  2790. this.postRenderTasks.forEach(t => t());
  2791. }
  2792. renderTheme (themePart, styleContainer) {
  2793. const variables = {};
  2794. const fontScheme = themePart.theme?.fontScheme;
  2795. if (fontScheme) {
  2796. if (fontScheme.majorFont) {
  2797. variables['--docx-majorHAnsi-font'] = fontScheme.majorFont.latinTypeface;
  2798. }
  2799. if (fontScheme.minorFont) {
  2800. variables['--docx-minorHAnsi-font'] = fontScheme.minorFont.latinTypeface;
  2801. }
  2802. }
  2803. const colorScheme = themePart.theme?.colorScheme;
  2804. if (colorScheme) {
  2805. for (let [k, v] of Object.entries(colorScheme.colors)) {
  2806. variables[`--docx-${k}-color`] = `#${v}`;
  2807. }
  2808. }
  2809. const cssText = this.styleToString(`.${this.className}`, variables);
  2810. styleContainer.appendChild(createStyleElement(cssText));
  2811. }
  2812. renderFontTable (fontsPart, styleContainer) {
  2813. for (let f of fontsPart.fonts) {
  2814. for (let ref of f.embedFontRefs) {
  2815. this.tasks.push(this.document.loadFont(ref.id, ref.key).then(fontData => {
  2816. const cssValues = {
  2817. 'font-family': f.name,
  2818. 'src': `url(${fontData})`
  2819. };
  2820. if (ref.type == "bold" || ref.type == "boldItalic") {
  2821. cssValues['font-weight'] = 'bold';
  2822. }
  2823. if (ref.type == "italic" || ref.type == "boldItalic") {
  2824. cssValues['font-style'] = 'italic';
  2825. }
  2826. appendComment(styleContainer, `docxjs ${f.name} font`);
  2827. const cssText = this.styleToString("@font-face", cssValues);
  2828. styleContainer.appendChild(createStyleElement(cssText));
  2829. this.refreshTabStops();
  2830. }));
  2831. }
  2832. }
  2833. }
  2834. processStyleName (className) {
  2835. return className ? `${this.className}_${escapeClassName(className)}` : this.className;
  2836. }
  2837. processStyles (styles) {
  2838. const stylesMap = keyBy(styles.filter(x => x.id != null), x => x.id);
  2839. for (const style of styles.filter(x => x.basedOn)) {
  2840. var baseStyle = stylesMap[style.basedOn];
  2841. if (baseStyle) {
  2842. style.paragraphProps = mergeDeep(style.paragraphProps, baseStyle.paragraphProps);
  2843. style.runProps = mergeDeep(style.runProps, baseStyle.runProps);
  2844. for (const baseValues of baseStyle.styles) {
  2845. const styleValues = style.styles.find(x => x.target == baseValues.target);
  2846. if (styleValues) {
  2847. this.copyStyleProperties(baseValues.values, styleValues.values);
  2848. }
  2849. else {
  2850. style.styles.push({ ...baseValues, values: { ...baseValues.values } });
  2851. }
  2852. }
  2853. }
  2854. else if (this.options.debug)
  2855. console.warn(`Can't find base style ${style.basedOn}`);
  2856. }
  2857. for (let style of styles) {
  2858. style.cssName = this.processStyleName(style.id);
  2859. }
  2860. return stylesMap;
  2861. }
  2862. prodessNumberings (numberings) {
  2863. for (let num of numberings.filter(n => n.pStyleName)) {
  2864. const style = this.findStyle(num.pStyleName);
  2865. if (style?.paragraphProps?.numbering) {
  2866. style.paragraphProps.numbering.level = num.level;
  2867. }
  2868. }
  2869. }
  2870. processElement (element) {
  2871. if (element.children) {
  2872. for (var e of element.children) {
  2873. e.parent = element;
  2874. if (e.type == DomType.Table) {
  2875. this.processTable(e);
  2876. }
  2877. else {
  2878. this.processElement(e);
  2879. }
  2880. }
  2881. }
  2882. }
  2883. processTable (table) {
  2884. for (var r of table.children) {
  2885. for (var c of r.children) {
  2886. c.cssStyle = this.copyStyleProperties(table.cellStyle, c.cssStyle, [
  2887. "border-left", "border-right", "border-top", "border-bottom",
  2888. "padding-left", "padding-right", "padding-top", "padding-bottom"
  2889. ]);
  2890. this.processElement(c);
  2891. }
  2892. }
  2893. }
  2894. copyStyleProperties (input, output, attrs = null) {
  2895. if (!input)
  2896. return output;
  2897. if (output == null)
  2898. output = {};
  2899. if (attrs == null)
  2900. attrs = Object.getOwnPropertyNames(input);
  2901. for (var key of attrs) {
  2902. if (input.hasOwnProperty(key) && !output.hasOwnProperty(key))
  2903. output[key] = input[key];
  2904. }
  2905. return output;
  2906. }
  2907. createPageElement (className, props) {
  2908. var elem = this.createElement("section", { className });
  2909. if (props) {
  2910. if (props.pageMargins) {
  2911. elem.style.paddingLeft = props.pageMargins.left;
  2912. elem.style.paddingRight = props.pageMargins.right;
  2913. elem.style.paddingTop = props.pageMargins.top;
  2914. elem.style.paddingBottom = props.pageMargins.bottom;
  2915. }
  2916. if (props.pageSize) {
  2917. if (!this.options.ignoreWidth)
  2918. elem.style.width = props.pageSize.width;
  2919. if (!this.options.ignoreHeight)
  2920. elem.style.minHeight = props.pageSize.height;
  2921. }
  2922. }
  2923. return elem;
  2924. }
  2925. createSectionContent (props) {
  2926. var elem = this.createElement("article");
  2927. if (props.columns && props.columns.numberOfColumns) {
  2928. elem.style.columnCount = `${props.columns.numberOfColumns}`;
  2929. elem.style.columnGap = props.columns.space;
  2930. if (props.columns.separator) {
  2931. elem.style.columnRule = "1px solid black";
  2932. }
  2933. }
  2934. return elem;
  2935. }
  2936. renderSections (document) {
  2937. const result = [];
  2938. this.processElement(document);
  2939. const sections = this.splitBySection(document.children, document.props);
  2940. const pages = this.groupByPageBreaks(sections);
  2941. let prevProps = null;
  2942. for (let i = 0, l = pages.length; i < l; i++) {
  2943. this.currentFootnoteIds = [];
  2944. const section = pages[i][0];
  2945. let props = section.sectProps;
  2946. const pageElement = this.createPageElement(this.className, props);
  2947. this.renderStyleValues(document.cssStyle, pageElement);
  2948. this.options.renderHeaders && this.renderHeaderFooter(props.headerRefs, props, result.length, prevProps != props, pageElement);
  2949. for (const sect of pages[i]) {
  2950. var contentElement = this.createSectionContent(sect.sectProps);
  2951. this.renderElements(sect.elements, contentElement);
  2952. pageElement.appendChild(contentElement);
  2953. props = sect.sectProps;
  2954. }
  2955. if (this.options.renderFootnotes) {
  2956. this.renderNotes(this.currentFootnoteIds, this.footnoteMap, pageElement);
  2957. }
  2958. if (this.options.renderEndnotes && i == l - 1) {
  2959. this.renderNotes(this.currentEndnoteIds, this.endnoteMap, pageElement);
  2960. }
  2961. this.options.renderFooters && this.renderHeaderFooter(props.footerRefs, props, result.length, prevProps != props, pageElement);
  2962. result.push(pageElement);
  2963. prevProps = props;
  2964. }
  2965. return result;
  2966. }
  2967. renderHeaderFooter (refs, props, page, firstOfSection, into) {
  2968. if (!refs)
  2969. return;
  2970. var ref = (props.titlePage && firstOfSection ? refs.find(x => x.type == "first") : null)
  2971. ?? (page % 2 == 1 ? refs.find(x => x.type == "even") : null)
  2972. ?? refs.find(x => x.type == "default");
  2973. var part = ref && this.document.findPartByRelId(ref.id, this.document.documentPart);
  2974. if (part) {
  2975. this.currentPart = part;
  2976. if (!this.usedHederFooterParts.includes(part.path)) {
  2977. this.processElement(part.rootElement);
  2978. this.usedHederFooterParts.push(part.path);
  2979. }
  2980. const [el] = this.renderElements([part.rootElement], into);
  2981. if (props?.pageMargins) {
  2982. if (part.rootElement.type === DomType.Header) {
  2983. el.style.marginTop = `calc(${props.pageMargins.header} - ${props.pageMargins.top})`;
  2984. el.style.minHeight = `calc(${props.pageMargins.top} - ${props.pageMargins.header})`;
  2985. }
  2986. else if (part.rootElement.type === DomType.Footer) {
  2987. el.style.marginBottom = `calc(${props.pageMargins.footer} - ${props.pageMargins.bottom})`;
  2988. el.style.minHeight = `calc(${props.pageMargins.bottom} - ${props.pageMargins.footer})`;
  2989. }
  2990. }
  2991. this.currentPart = null;
  2992. }
  2993. }
  2994. isPageBreakElement (elem) {
  2995. if (elem.type != DomType.Break)
  2996. return false;
  2997. if (elem.break == "lastRenderedPageBreak")
  2998. return !this.options.ignoreLastRenderedPageBreak;
  2999. return elem.break == "page";
  3000. }
  3001. isPageBreakSection (prev, next) {
  3002. if (!prev)
  3003. return false;
  3004. if (!next)
  3005. return false;
  3006. return prev.pageSize?.orientation != next.pageSize?.orientation
  3007. || prev.pageSize?.width != next.pageSize?.width
  3008. || prev.pageSize?.height != next.pageSize?.height;
  3009. }
  3010. splitBySection (elements, defaultProps) {
  3011. var current = { sectProps: null, elements: [], pageBreak: false };
  3012. var result = [current];
  3013. for (let elem of elements) {
  3014. if (elem.type == DomType.Paragraph) {
  3015. const s = this.findStyle(elem.styleName);
  3016. if (s?.paragraphProps?.pageBreakBefore) {
  3017. current.sectProps = sectProps;
  3018. current.pageBreak = true;
  3019. current = { sectProps: null, elements: [], pageBreak: false };
  3020. result.push(current);
  3021. }
  3022. }
  3023. current.elements.push(elem);
  3024. if (elem.type == DomType.Paragraph) {
  3025. const p = elem;
  3026. var sectProps = p.sectionProps;
  3027. var pBreakIndex = -1;
  3028. var rBreakIndex = -1;
  3029. if (this.options.breakPages && p.children) {
  3030. pBreakIndex = p.children.findIndex(r => {
  3031. rBreakIndex = r.children?.findIndex(this.isPageBreakElement.bind(this)) ?? -1;
  3032. return rBreakIndex != -1;
  3033. });
  3034. }
  3035. if (sectProps || pBreakIndex != -1) {
  3036. current.sectProps = sectProps;
  3037. current.pageBreak = pBreakIndex != -1;
  3038. current = { sectProps: null, elements: [], pageBreak: false };
  3039. result.push(current);
  3040. }
  3041. if (pBreakIndex != -1) {
  3042. let breakRun = p.children[pBreakIndex];
  3043. let splitRun = rBreakIndex < breakRun.children.length - 1;
  3044. if (pBreakIndex < p.children.length - 1 || splitRun) {
  3045. var children = elem.children;
  3046. var newParagraph = { ...elem, children: children.slice(pBreakIndex) };
  3047. elem.children = children.slice(0, pBreakIndex);
  3048. current.elements.push(newParagraph);
  3049. if (splitRun) {
  3050. let runChildren = breakRun.children;
  3051. let newRun = { ...breakRun, children: runChildren.slice(0, rBreakIndex) };
  3052. elem.children.push(newRun);
  3053. breakRun.children = runChildren.slice(rBreakIndex);
  3054. }
  3055. }
  3056. }
  3057. }
  3058. }
  3059. let currentSectProps = null;
  3060. for (let i = result.length - 1; i >= 0; i--) {
  3061. if (result[i].sectProps == null) {
  3062. result[i].sectProps = currentSectProps ?? defaultProps;
  3063. }
  3064. else {
  3065. currentSectProps = result[i].sectProps;
  3066. }
  3067. }
  3068. return result;
  3069. }
  3070. groupByPageBreaks (sections) {
  3071. let current = [];
  3072. let prev;
  3073. const result = [current];
  3074. for (let s of sections) {
  3075. current.push(s);
  3076. if (this.options.ignoreLastRenderedPageBreak || s.pageBreak || this.isPageBreakSection(prev, s.sectProps))
  3077. result.push(current = []);
  3078. prev = s.sectProps;
  3079. }
  3080. return result.filter(x => x.length > 0);
  3081. }
  3082. renderWrapper (children) {
  3083. return this.createElement("div", { className: `${this.className}-wrapper` }, children);
  3084. }
  3085. renderDefaultStyle () {
  3086. var c = this.className;
  3087. var styleText = `
  3088. .${c}-wrapper { background: gray; padding: 30px; padding-bottom: 0px; display: flex; flex-flow: column; align-items: center; }
  3089. .${c}-wrapper>section.${c} { background: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); margin-bottom: 30px; }
  3090. .${c} { color: black; hyphens: auto; text-underline-position: from-font; }
  3091. section.${c} { box-sizing: border-box; display: flex; flex-flow: column nowrap; position: relative; overflow: hidden; }
  3092. section.${c}>article { margin-bottom: auto; z-index: 1; }
  3093. section.${c}>footer { z-index: 1; }
  3094. .${c} table { border-collapse: collapse; }
  3095. .${c} table td, .${c} table th { vertical-align: top; }
  3096. .${c} p { margin: 0pt; min-height: 1em; }
  3097. .${c} span { white-space: pre-wrap; overflow-wrap: break-word; }
  3098. .${c} a { color: inherit; text-decoration: inherit; }
  3099. .${c} svg { fill: transparent; }
  3100. `;
  3101. if (this.options.renderComments) {
  3102. styleText += `
  3103. .${c}-comment-ref { cursor: default; }
  3104. .${c}-comment-popover { display: none; z-index: 1000; padding: 0.5rem; background: white; position: absolute; box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.25); width: 30ch; }
  3105. .${c}-comment-ref:hover~.${c}-comment-popover { display: block; }
  3106. .${c}-comment-author,.${c}-comment-date { font-size: 0.875rem; color: #888; }
  3107. `;
  3108. }
  3109. return createStyleElement(styleText);
  3110. }
  3111. renderNumbering (numberings, styleContainer) {
  3112. var styleText = "";
  3113. var resetCounters = [];
  3114. for (var num of numberings) {
  3115. var selector = `p.${this.numberingClass(num.id, num.level)}`;
  3116. var listStyleType = "none";
  3117. if (num.bullet) {
  3118. let valiable = `--${this.className}-${num.bullet.src}`.toLowerCase();
  3119. styleText += this.styleToString(`${selector}:before`, {
  3120. "content": "' '",
  3121. "display": "inline-block",
  3122. "background": `var(${valiable})`
  3123. }, num.bullet.style);
  3124. this.tasks.push(this.document.loadNumberingImage(num.bullet.src).then(data => {
  3125. var text = `${this.rootSelector} { ${valiable}: url(${data}) }`;
  3126. styleContainer.appendChild(createStyleElement(text));
  3127. }));
  3128. }
  3129. else if (num.levelText) {
  3130. let counter = this.numberingCounter(num.id, num.level);
  3131. const counterReset = counter + " " + (num.start - 1);
  3132. if (num.level > 0) {
  3133. styleText += this.styleToString(`p.${this.numberingClass(num.id, num.level - 1)}`, {
  3134. "counter-reset": counterReset
  3135. });
  3136. }
  3137. resetCounters.push(counterReset);
  3138. styleText += this.styleToString(`${selector}:before`, {
  3139. "content": this.levelTextToContent(num.levelText, num.suff, num.id, this.numFormatToCssValue(num.format)),
  3140. "counter-increment": counter,
  3141. ...num.rStyle,
  3142. });
  3143. }
  3144. else {
  3145. listStyleType = this.numFormatToCssValue(num.format);
  3146. }
  3147. styleText += this.styleToString(selector, {
  3148. "display": "list-item",
  3149. "list-style-position": "inside",
  3150. "list-style-type": listStyleType,
  3151. ...num.pStyle
  3152. });
  3153. }
  3154. if (resetCounters.length > 0) {
  3155. styleText += this.styleToString(this.rootSelector, {
  3156. "counter-reset": resetCounters.join(" ")
  3157. });
  3158. }
  3159. return createStyleElement(styleText);
  3160. }
  3161. renderStyles (styles) {
  3162. var styleText = "";
  3163. const stylesMap = this.styleMap;
  3164. const defautStyles = keyBy(styles.filter(s => s.isDefault), s => s.target);
  3165. for (const style of styles) {
  3166. var subStyles = style.styles;
  3167. if (style.linked) {
  3168. var linkedStyle = style.linked && stylesMap[style.linked];
  3169. if (linkedStyle)
  3170. subStyles = subStyles.concat(linkedStyle.styles);
  3171. else if (this.options.debug)
  3172. console.warn(`Can't find linked style ${style.linked}`);
  3173. }
  3174. for (const subStyle of subStyles) {
  3175. var selector = `${style.target ?? ''}.${style.cssName}`;
  3176. if (style.target != subStyle.target)
  3177. selector += ` ${subStyle.target}`;
  3178. if (defautStyles[style.target] == style)
  3179. selector = `.${this.className} ${style.target}, ` + selector;
  3180. styleText += this.styleToString(selector, subStyle.values);
  3181. }
  3182. }
  3183. return createStyleElement(styleText);
  3184. }
  3185. renderNotes (noteIds, notesMap, into) {
  3186. var notes = noteIds.map(id => notesMap[id]).filter(x => x);
  3187. if (notes.length > 0) {
  3188. var result = this.createElement("ol", null, this.renderElements(notes));
  3189. into.appendChild(result);
  3190. }
  3191. }
  3192. renderElement (elem) {
  3193. switch (elem.type) {
  3194. case DomType.Paragraph:
  3195. return this.renderParagraph(elem);
  3196. case DomType.BookmarkStart:
  3197. return this.renderBookmarkStart(elem);
  3198. case DomType.BookmarkEnd:
  3199. return null;
  3200. case DomType.Run:
  3201. return this.renderRun(elem);
  3202. case DomType.Table:
  3203. return this.renderTable(elem);
  3204. case DomType.Row:
  3205. return this.renderTableRow(elem);
  3206. case DomType.Cell:
  3207. return this.renderTableCell(elem);
  3208. case DomType.Hyperlink:
  3209. return this.renderHyperlink(elem);
  3210. case DomType.SmartTag:
  3211. return this.renderSmartTag(elem);
  3212. case DomType.Drawing:
  3213. return this.renderDrawing(elem);
  3214. case DomType.Image:
  3215. return this.renderImage(elem);
  3216. case DomType.Text:
  3217. return this.renderText(elem);
  3218. case DomType.Text:
  3219. return this.renderText(elem);
  3220. case DomType.DeletedText:
  3221. return this.renderDeletedText(elem);
  3222. case DomType.Tab:
  3223. return this.renderTab(elem);
  3224. case DomType.Symbol:
  3225. return this.renderSymbol(elem);
  3226. case DomType.Break:
  3227. return this.renderBreak(elem);
  3228. case DomType.Footer:
  3229. return this.renderContainer(elem, "footer");
  3230. case DomType.Header:
  3231. return this.renderContainer(elem, "header");
  3232. case DomType.Footnote:
  3233. case DomType.Endnote:
  3234. return this.renderContainer(elem, "li");
  3235. case DomType.FootnoteReference:
  3236. return this.renderFootnoteReference(elem);
  3237. case DomType.EndnoteReference:
  3238. return this.renderEndnoteReference(elem);
  3239. case DomType.NoBreakHyphen:
  3240. return this.createElement("wbr");
  3241. case DomType.VmlPicture:
  3242. return this.renderVmlPicture(elem);
  3243. case DomType.VmlElement:
  3244. return this.renderVmlElement(elem);
  3245. case DomType.MmlMath:
  3246. return this.renderContainerNS(elem, ns.mathML, "math", { xmlns: ns.mathML });
  3247. case DomType.MmlMathParagraph:
  3248. return this.renderContainer(elem, "span");
  3249. case DomType.MmlFraction:
  3250. return this.renderContainerNS(elem, ns.mathML, "mfrac");
  3251. case DomType.MmlBase:
  3252. return this.renderContainerNS(elem, ns.mathML, elem.parent.type == DomType.MmlMatrixRow ? "mtd" : "mrow");
  3253. case DomType.MmlNumerator:
  3254. case DomType.MmlDenominator:
  3255. case DomType.MmlFunction:
  3256. case DomType.MmlLimit:
  3257. case DomType.MmlBox:
  3258. return this.renderContainerNS(elem, ns.mathML, "mrow");
  3259. case DomType.MmlGroupChar:
  3260. return this.renderMmlGroupChar(elem);
  3261. case DomType.MmlLimitLower:
  3262. return this.renderContainerNS(elem, ns.mathML, "munder");
  3263. case DomType.MmlMatrix:
  3264. return this.renderContainerNS(elem, ns.mathML, "mtable");
  3265. case DomType.MmlMatrixRow:
  3266. return this.renderContainerNS(elem, ns.mathML, "mtr");
  3267. case DomType.MmlRadical:
  3268. return this.renderMmlRadical(elem);
  3269. case DomType.MmlSuperscript:
  3270. return this.renderContainerNS(elem, ns.mathML, "msup");
  3271. case DomType.MmlSubscript:
  3272. return this.renderContainerNS(elem, ns.mathML, "msub");
  3273. case DomType.MmlDegree:
  3274. case DomType.MmlSuperArgument:
  3275. case DomType.MmlSubArgument:
  3276. return this.renderContainerNS(elem, ns.mathML, "mn");
  3277. case DomType.MmlFunctionName:
  3278. return this.renderContainerNS(elem, ns.mathML, "ms");
  3279. case DomType.MmlDelimiter:
  3280. return this.renderMmlDelimiter(elem);
  3281. case DomType.MmlRun:
  3282. return this.renderMmlRun(elem);
  3283. case DomType.MmlNary:
  3284. return this.renderMmlNary(elem);
  3285. case DomType.MmlPreSubSuper:
  3286. return this.renderMmlPreSubSuper(elem);
  3287. case DomType.MmlBar:
  3288. return this.renderMmlBar(elem);
  3289. case DomType.MmlEquationArray:
  3290. return this.renderMllList(elem);
  3291. case DomType.Inserted:
  3292. return this.renderInserted(elem);
  3293. case DomType.Deleted:
  3294. return this.renderDeleted(elem);
  3295. case DomType.CommentRangeStart:
  3296. return this.renderCommentRangeStart(elem);
  3297. case DomType.CommentRangeEnd:
  3298. return this.renderCommentRangeEnd(elem);
  3299. case DomType.CommentReference:
  3300. return this.renderCommentReference(elem);
  3301. }
  3302. return null;
  3303. }
  3304. renderChildren (elem, into) {
  3305. return this.renderElements(elem.children, into);
  3306. }
  3307. renderElements (elems, into) {
  3308. if (elems == null)
  3309. return null;
  3310. var result = elems.flatMap(e => this.renderElement(e)).filter(e => e != null);
  3311. if (into)
  3312. appendChildren(into, result);
  3313. return result;
  3314. }
  3315. renderContainer (elem, tagName, props) {
  3316. return this.createElement(tagName, props, this.renderChildren(elem));
  3317. }
  3318. renderContainerNS (elem, ns, tagName, props) {
  3319. return createElementNS(ns, tagName, props, this.renderChildren(elem));
  3320. }
  3321. renderParagraph (elem) {
  3322. var result = this.createElement("p");
  3323. const style = this.findStyle(elem.styleName);
  3324. elem.tabs ?? (elem.tabs = style?.paragraphProps?.tabs);
  3325. this.renderClass(elem, result);
  3326. this.renderChildren(elem, result);
  3327. this.renderStyleValues(elem.cssStyle, result);
  3328. this.renderCommonProperties(result.style, elem);
  3329. const numbering = elem.numbering ?? style?.paragraphProps?.numbering;
  3330. if (numbering) {
  3331. result.classList.add(this.numberingClass(numbering.id, numbering.level));
  3332. }
  3333. return result;
  3334. }
  3335. renderRunProperties (style, props) {
  3336. this.renderCommonProperties(style, props);
  3337. }
  3338. renderCommonProperties (style, props) {
  3339. if (props == null)
  3340. return;
  3341. if (props.color) {
  3342. style["color"] = props.color;
  3343. }
  3344. if (props.fontSize) {
  3345. style["font-size"] = props.fontSize;
  3346. }
  3347. }
  3348. renderHyperlink (elem) {
  3349. var result = this.createElement("a");
  3350. this.renderChildren(elem, result);
  3351. this.renderStyleValues(elem.cssStyle, result);
  3352. if (elem.href) {
  3353. result.href = elem.href;
  3354. }
  3355. else if (elem.id) {
  3356. const rel = this.document.documentPart.rels
  3357. .find(it => it.id == elem.id && it.targetMode === "External");
  3358. result.href = rel?.target;
  3359. }
  3360. return result;
  3361. }
  3362. renderSmartTag (elem) {
  3363. var result = this.createElement("span");
  3364. this.renderChildren(elem, result);
  3365. return result;
  3366. }
  3367. renderCommentRangeStart (commentStart) {
  3368. if (!this.options.renderComments)
  3369. return null;
  3370. const rng = new Range();
  3371. this.commentHighlight?.add(rng);
  3372. const result = this.htmlDocument.createComment(`start of comment #${commentStart.id}`);
  3373. this.later(() => rng.setStart(result, 0));
  3374. this.commentMap[commentStart.id] = rng;
  3375. return result;
  3376. }
  3377. renderCommentRangeEnd (commentEnd) {
  3378. if (!this.options.renderComments)
  3379. return null;
  3380. const rng = this.commentMap[commentEnd.id];
  3381. const result = this.htmlDocument.createComment(`end of comment #${commentEnd.id}`);
  3382. this.later(() => rng?.setEnd(result, 0));
  3383. return result;
  3384. }
  3385. renderCommentReference (commentRef) {
  3386. if (!this.options.renderComments)
  3387. return null;
  3388. var comment = this.document.commentsPart?.commentMap[commentRef.id];
  3389. if (!comment)
  3390. return null;
  3391. const frg = new DocumentFragment();
  3392. const commentRefEl = createElement("span", { className: `${this.className}-comment-ref` }, ['💬']);
  3393. const commentsContainerEl = createElement("div", { className: `${this.className}-comment-popover` });
  3394. this.renderCommentContent(comment, commentsContainerEl);
  3395. frg.appendChild(this.htmlDocument.createComment(`comment #${comment.id} by ${comment.author} on ${comment.date}`));
  3396. frg.appendChild(commentRefEl);
  3397. frg.appendChild(commentsContainerEl);
  3398. return frg;
  3399. }
  3400. renderCommentContent (comment, container) {
  3401. container.appendChild(createElement('div', { className: `${this.className}-comment-author` }, [comment.author]));
  3402. container.appendChild(createElement('div', { className: `${this.className}-comment-date` }, [new Date(comment.date).toLocaleString()]));
  3403. this.renderChildren(comment, container);
  3404. }
  3405. renderDrawing (elem) {
  3406. var result = this.createElement("div");
  3407. result.style.display = "inline-block";
  3408. result.style.position = "relative";
  3409. result.style.textIndent = "0px";
  3410. this.renderChildren(elem, result);
  3411. this.renderStyleValues(elem.cssStyle, result);
  3412. return result;
  3413. }
  3414. renderImage (elem) {
  3415. let result = this.createElement("img");
  3416. this.renderStyleValues(elem.cssStyle, result);
  3417. if (this.document) {
  3418. this.tasks.push(this.document.loadDocumentImage(elem.src, this.currentPart).then(x => {
  3419. result.src = x;
  3420. }));
  3421. }
  3422. return result;
  3423. }
  3424. renderText (elem) {
  3425. return this.htmlDocument.createTextNode(elem.text);
  3426. }
  3427. renderDeletedText (elem) {
  3428. return this.options.renderEndnotes ? this.htmlDocument.createTextNode(elem.text) : null;
  3429. }
  3430. renderBreak (elem) {
  3431. if (elem.break == "textWrapping") {
  3432. return this.createElement("br");
  3433. }
  3434. return null;
  3435. }
  3436. renderInserted (elem) {
  3437. if (this.options.renderChanges)
  3438. return this.renderContainer(elem, "ins");
  3439. return this.renderChildren(elem);
  3440. }
  3441. renderDeleted (elem) {
  3442. if (this.options.renderChanges)
  3443. return this.renderContainer(elem, "del");
  3444. return null;
  3445. }
  3446. renderSymbol (elem) {
  3447. var span = this.createElement("span");
  3448. span.style.fontFamily = elem.font;
  3449. span.innerHTML = `&#x${elem.char};`;
  3450. return span;
  3451. }
  3452. renderFootnoteReference (elem) {
  3453. var result = this.createElement("sup");
  3454. this.currentFootnoteIds.push(elem.id);
  3455. result.textContent = `${this.currentFootnoteIds.length}`;
  3456. return result;
  3457. }
  3458. renderEndnoteReference (elem) {
  3459. var result = this.createElement("sup");
  3460. this.currentEndnoteIds.push(elem.id);
  3461. result.textContent = `${this.currentEndnoteIds.length}`;
  3462. return result;
  3463. }
  3464. renderTab (elem) {
  3465. var tabSpan = this.createElement("span");
  3466. tabSpan.innerHTML = "&emsp;";
  3467. if (this.options.experimental) {
  3468. tabSpan.className = this.tabStopClass();
  3469. var stops = findParent(elem, DomType.Paragraph)?.tabs;
  3470. this.currentTabs.push({ stops, span: tabSpan });
  3471. }
  3472. return tabSpan;
  3473. }
  3474. renderBookmarkStart (elem) {
  3475. var result = this.createElement("span");
  3476. result.id = elem.name;
  3477. return result;
  3478. }
  3479. renderRun (elem) {
  3480. if (elem.fieldRun)
  3481. return null;
  3482. const result = this.createElement("span");
  3483. if (elem.id)
  3484. result.id = elem.id;
  3485. this.renderClass(elem, result);
  3486. this.renderStyleValues(elem.cssStyle, result);
  3487. if (elem.verticalAlign) {
  3488. const wrapper = this.createElement(elem.verticalAlign);
  3489. this.renderChildren(elem, wrapper);
  3490. result.appendChild(wrapper);
  3491. }
  3492. else {
  3493. this.renderChildren(elem, result);
  3494. }
  3495. return result;
  3496. }
  3497. renderTable (elem) {
  3498. let result = this.createElement("table");
  3499. this.tableCellPositions.push(this.currentCellPosition);
  3500. this.tableVerticalMerges.push(this.currentVerticalMerge);
  3501. this.currentVerticalMerge = {};
  3502. this.currentCellPosition = { col: 0, row: 0 };
  3503. if (elem.columns)
  3504. result.appendChild(this.renderTableColumns(elem.columns));
  3505. this.renderClass(elem, result);
  3506. this.renderChildren(elem, result);
  3507. this.renderStyleValues(elem.cssStyle, result);
  3508. this.currentVerticalMerge = this.tableVerticalMerges.pop();
  3509. this.currentCellPosition = this.tableCellPositions.pop();
  3510. return result;
  3511. }
  3512. renderTableColumns (columns) {
  3513. let result = this.createElement("colgroup");
  3514. for (let col of columns) {
  3515. let colElem = this.createElement("col");
  3516. if (col.width)
  3517. colElem.style.width = col.width;
  3518. result.appendChild(colElem);
  3519. }
  3520. return result;
  3521. }
  3522. renderTableRow (elem) {
  3523. let result = this.createElement("tr");
  3524. this.currentCellPosition.col = 0;
  3525. this.renderClass(elem, result);
  3526. this.renderChildren(elem, result);
  3527. this.renderStyleValues(elem.cssStyle, result);
  3528. this.currentCellPosition.row++;
  3529. return result;
  3530. }
  3531. renderTableCell (elem) {
  3532. let result = this.createElement("td");
  3533. const key = this.currentCellPosition.col;
  3534. if (elem.verticalMerge) {
  3535. if (elem.verticalMerge == "restart") {
  3536. this.currentVerticalMerge[key] = result;
  3537. result.rowSpan = 1;
  3538. }
  3539. else if (this.currentVerticalMerge[key]) {
  3540. this.currentVerticalMerge[key].rowSpan += 1;
  3541. result.style.display = "none";
  3542. }
  3543. }
  3544. else {
  3545. this.currentVerticalMerge[key] = null;
  3546. }
  3547. this.renderClass(elem, result);
  3548. this.renderChildren(elem, result);
  3549. this.renderStyleValues(elem.cssStyle, result);
  3550. if (elem.span)
  3551. result.colSpan = elem.span;
  3552. this.currentCellPosition.col += result.colSpan;
  3553. return result;
  3554. }
  3555. renderVmlPicture (elem) {
  3556. var result = createElement("div");
  3557. this.renderChildren(elem, result);
  3558. return result;
  3559. }
  3560. renderVmlElement (elem) {
  3561. var container = createSvgElement("svg");
  3562. container.setAttribute("style", elem.cssStyleText);
  3563. const result = this.renderVmlChildElement(elem);
  3564. if (elem.imageHref?.id) {
  3565. this.tasks.push(this.document?.loadDocumentImage(elem.imageHref.id, this.currentPart)
  3566. .then(x => result.setAttribute("href", x)));
  3567. }
  3568. container.appendChild(result);
  3569. requestAnimationFrame(() => {
  3570. const bb = container.firstElementChild.getBBox();
  3571. container.setAttribute("width", `${Math.ceil(bb.x + bb.width)}`);
  3572. container.setAttribute("height", `${Math.ceil(bb.y + bb.height)}`);
  3573. });
  3574. return container;
  3575. }
  3576. renderVmlChildElement (elem) {
  3577. const result = createSvgElement(elem.tagName);
  3578. Object.entries(elem.attrs).forEach(([k, v]) => result.setAttribute(k, v));
  3579. for (let child of elem.children) {
  3580. if (child.type == DomType.VmlElement) {
  3581. result.appendChild(this.renderVmlChildElement(child));
  3582. }
  3583. else {
  3584. result.appendChild(...asArray(this.renderElement(child)));
  3585. }
  3586. }
  3587. return result;
  3588. }
  3589. renderMmlRadical (elem) {
  3590. const base = elem.children.find(el => el.type == DomType.MmlBase);
  3591. if (elem.props?.hideDegree) {
  3592. return createElementNS(ns.mathML, "msqrt", null, this.renderElements([base]));
  3593. }
  3594. const degree = elem.children.find(el => el.type == DomType.MmlDegree);
  3595. return createElementNS(ns.mathML, "mroot", null, this.renderElements([base, degree]));
  3596. }
  3597. renderMmlDelimiter (elem) {
  3598. const children = [];
  3599. children.push(createElementNS(ns.mathML, "mo", null, [elem.props.beginChar ?? '(']));
  3600. children.push(...this.renderElements(elem.children));
  3601. children.push(createElementNS(ns.mathML, "mo", null, [elem.props.endChar ?? ')']));
  3602. return createElementNS(ns.mathML, "mrow", null, children);
  3603. }
  3604. renderMmlNary (elem) {
  3605. const children = [];
  3606. const grouped = keyBy(elem.children, x => x.type);
  3607. const sup = grouped[DomType.MmlSuperArgument];
  3608. const sub = grouped[DomType.MmlSubArgument];
  3609. const supElem = sup ? createElementNS(ns.mathML, "mo", null, asArray(this.renderElement(sup))) : null;
  3610. const subElem = sub ? createElementNS(ns.mathML, "mo", null, asArray(this.renderElement(sub))) : null;
  3611. const charElem = createElementNS(ns.mathML, "mo", null, [elem.props?.char ?? '\u222B']);
  3612. if (supElem || subElem) {
  3613. children.push(createElementNS(ns.mathML, "munderover", null, [charElem, subElem, supElem]));
  3614. }
  3615. else if (supElem) {
  3616. children.push(createElementNS(ns.mathML, "mover", null, [charElem, supElem]));
  3617. }
  3618. else if (subElem) {
  3619. children.push(createElementNS(ns.mathML, "munder", null, [charElem, subElem]));
  3620. }
  3621. else {
  3622. children.push(charElem);
  3623. }
  3624. children.push(...this.renderElements(grouped[DomType.MmlBase].children));
  3625. return createElementNS(ns.mathML, "mrow", null, children);
  3626. }
  3627. renderMmlPreSubSuper (elem) {
  3628. const children = [];
  3629. const grouped = keyBy(elem.children, x => x.type);
  3630. const sup = grouped[DomType.MmlSuperArgument];
  3631. const sub = grouped[DomType.MmlSubArgument];
  3632. const supElem = sup ? createElementNS(ns.mathML, "mo", null, asArray(this.renderElement(sup))) : null;
  3633. const subElem = sub ? createElementNS(ns.mathML, "mo", null, asArray(this.renderElement(sub))) : null;
  3634. const stubElem = createElementNS(ns.mathML, "mo", null);
  3635. children.push(createElementNS(ns.mathML, "msubsup", null, [stubElem, subElem, supElem]));
  3636. children.push(...this.renderElements(grouped[DomType.MmlBase].children));
  3637. return createElementNS(ns.mathML, "mrow", null, children);
  3638. }
  3639. renderMmlGroupChar (elem) {
  3640. const tagName = elem.props.verticalJustification === "bot" ? "mover" : "munder";
  3641. const result = this.renderContainerNS(elem, ns.mathML, tagName);
  3642. if (elem.props.char) {
  3643. result.appendChild(createElementNS(ns.mathML, "mo", null, [elem.props.char]));
  3644. }
  3645. return result;
  3646. }
  3647. renderMmlBar (elem) {
  3648. const result = this.renderContainerNS(elem, ns.mathML, "mrow");
  3649. switch (elem.props.position) {
  3650. case "top":
  3651. result.style.textDecoration = "overline";
  3652. break;
  3653. case "bottom":
  3654. result.style.textDecoration = "underline";
  3655. break;
  3656. }
  3657. return result;
  3658. }
  3659. renderMmlRun (elem) {
  3660. const result = createElementNS(ns.mathML, "ms");
  3661. this.renderClass(elem, result);
  3662. this.renderStyleValues(elem.cssStyle, result);
  3663. this.renderChildren(elem, result);
  3664. return result;
  3665. }
  3666. renderMllList (elem) {
  3667. const result = createElementNS(ns.mathML, "mtable");
  3668. this.renderClass(elem, result);
  3669. this.renderStyleValues(elem.cssStyle, result);
  3670. this.renderChildren(elem);
  3671. for (let child of this.renderChildren(elem)) {
  3672. result.appendChild(createElementNS(ns.mathML, "mtr", null, [
  3673. createElementNS(ns.mathML, "mtd", null, [child])
  3674. ]));
  3675. }
  3676. return result;
  3677. }
  3678. renderStyleValues (style, ouput) {
  3679. for (let k in style) {
  3680. if (k.startsWith("$")) {
  3681. ouput.setAttribute(k.slice(1), style[k]);
  3682. }
  3683. else {
  3684. ouput.style[k] = style[k];
  3685. }
  3686. }
  3687. }
  3688. renderClass (input, ouput) {
  3689. if (input.className)
  3690. ouput.className = input.className;
  3691. if (input.styleName)
  3692. ouput.classList.add(this.processStyleName(input.styleName));
  3693. }
  3694. findStyle (styleName) {
  3695. return styleName && this.styleMap?.[styleName];
  3696. }
  3697. numberingClass (id, lvl) {
  3698. return `${this.className}-num-${id}-${lvl}`;
  3699. }
  3700. tabStopClass () {
  3701. return `${this.className}-tab-stop`;
  3702. }
  3703. styleToString (selectors, values, cssText = null) {
  3704. let result = `${selectors} {\r\n`;
  3705. for (const key in values) {
  3706. if (key.startsWith('$'))
  3707. continue;
  3708. result += ` ${key}: ${values[key]};\r\n`;
  3709. }
  3710. if (cssText)
  3711. result += cssText;
  3712. return result + "}\r\n";
  3713. }
  3714. numberingCounter (id, lvl) {
  3715. return `${this.className}-num-${id}-${lvl}`;
  3716. }
  3717. levelTextToContent (text, suff, id, numformat) {
  3718. const suffMap = {
  3719. "tab": "\\9",
  3720. "space": "\\a0",
  3721. };
  3722. var result = text.replace(/%\d*/g, s => {
  3723. let lvl = parseInt(s.substring(1), 10) - 1;
  3724. return `"counter(${this.numberingCounter(id, lvl)}, ${numformat})"`;
  3725. });
  3726. return `"${result}${suffMap[suff] ?? ""}"`;
  3727. }
  3728. numFormatToCssValue (format) {
  3729. var mapping = {
  3730. none: "none",
  3731. bullet: "disc",
  3732. decimal: "decimal",
  3733. lowerLetter: "lower-alpha",
  3734. upperLetter: "upper-alpha",
  3735. lowerRoman: "lower-roman",
  3736. upperRoman: "upper-roman",
  3737. decimalZero: "decimal-leading-zero",
  3738. aiueo: "katakana",
  3739. aiueoFullWidth: "katakana",
  3740. chineseCounting: "simp-chinese-informal",
  3741. chineseCountingThousand: "simp-chinese-informal",
  3742. chineseLegalSimplified: "simp-chinese-formal",
  3743. chosung: "hangul-consonant",
  3744. ideographDigital: "cjk-ideographic",
  3745. ideographTraditional: "cjk-heavenly-stem",
  3746. ideographLegalTraditional: "trad-chinese-formal",
  3747. ideographZodiac: "cjk-earthly-branch",
  3748. iroha: "katakana-iroha",
  3749. irohaFullWidth: "katakana-iroha",
  3750. japaneseCounting: "japanese-informal",
  3751. japaneseDigitalTenThousand: "cjk-decimal",
  3752. japaneseLegal: "japanese-formal",
  3753. thaiNumbers: "thai",
  3754. koreanCounting: "korean-hangul-formal",
  3755. koreanDigital: "korean-hangul-formal",
  3756. koreanDigital2: "korean-hanja-informal",
  3757. hebrew1: "hebrew",
  3758. hebrew2: "hebrew",
  3759. hindiNumbers: "devanagari",
  3760. ganada: "hangul",
  3761. taiwaneseCounting: "cjk-ideographic",
  3762. taiwaneseCountingThousand: "cjk-ideographic",
  3763. taiwaneseDigital: "cjk-decimal",
  3764. };
  3765. return mapping[format] ?? format;
  3766. }
  3767. refreshTabStops () {
  3768. if (!this.options.experimental)
  3769. return;
  3770. clearTimeout(this.tabsTimeout);
  3771. this.tabsTimeout = setTimeout(() => {
  3772. const pixelToPoint = computePixelToPoint();
  3773. for (let tab of this.currentTabs) {
  3774. updateTabStop(tab.span, tab.stops, this.defaultTabSize, pixelToPoint);
  3775. }
  3776. }, 500);
  3777. }
  3778. later (func) {
  3779. this.postRenderTasks.push(func);
  3780. }
  3781. }
  3782. function createElement (tagName, props, children) {
  3783. return createElementNS(undefined, tagName, props, children);
  3784. }
  3785. function createSvgElement (tagName, props, children) {
  3786. return createElementNS(ns.svg, tagName, props, children);
  3787. }
  3788. function createElementNS (ns, tagName, props, children) {
  3789. var result = ns ? document.createElementNS(ns, tagName) : document.createElement(tagName);
  3790. Object.assign(result, props);
  3791. children && appendChildren(result, children);
  3792. return result;
  3793. }
  3794. function removeAllElements (elem) {
  3795. elem.innerHTML = '';
  3796. }
  3797. function appendChildren (elem, children) {
  3798. children.forEach(c => elem.appendChild(isString(c) ? document.createTextNode(c) : c));
  3799. }
  3800. function createStyleElement (cssText) {
  3801. return createElement("style", { innerHTML: cssText });
  3802. }
  3803. function appendComment (elem, comment) {
  3804. elem.appendChild(document.createComment(comment));
  3805. }
  3806. function findParent (elem, type) {
  3807. var parent = elem.parent;
  3808. while (parent != null && parent.type != type)
  3809. parent = parent.parent;
  3810. return parent;
  3811. }
  3812. const defaultOptions = {
  3813. ignoreHeight: false,
  3814. ignoreWidth: false,
  3815. ignoreFonts: false,
  3816. breakPages: true,
  3817. debug: false,
  3818. experimental: false,
  3819. className: "docx",
  3820. inWrapper: true,
  3821. trimXmlDeclaration: true,
  3822. ignoreLastRenderedPageBreak: true,
  3823. renderHeaders: true,
  3824. renderFooters: true,
  3825. renderFootnotes: true,
  3826. renderEndnotes: true,
  3827. useBase64URL: false,
  3828. renderChanges: false,
  3829. renderComments: false
  3830. };
  3831. function parseAsync (data, userOptions) {
  3832. const ops = { ...defaultOptions, ...userOptions };
  3833. return WordDocument.load(data, new DocumentParser(ops), ops);
  3834. }
  3835. async function renderDocument (document, bodyContainer, styleContainer, userOptions) {
  3836. const ops = { ...defaultOptions, ...userOptions };
  3837. const renderer = new HtmlRenderer(window.document);
  3838. renderer.render(document, bodyContainer, styleContainer, ops);
  3839. return Promise.allSettled(renderer.tasks);
  3840. }
  3841. async function renderAsync (data, bodyContainer, styleContainer, userOptions) {
  3842. const doc = await parseAsync(data, userOptions);
  3843. await renderDocument(doc, bodyContainer, styleContainer, userOptions);
  3844. return doc;
  3845. }
  3846. exports.defaultOptions = defaultOptions;
  3847. exports.parseAsync = parseAsync;
  3848. exports.renderAsync = renderAsync;
  3849. exports.renderDocument = renderDocument;
  3850. }));
  3851. //# sourceMappingURL=docx-preview.js.map