@memberjunction/ng-markdown 6.2.0-edge.2 → 6.2.0-edge.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/lib/components/markdown.component.d.ts +6 -1
- package/dist/lib/components/markdown.component.d.ts.map +1 -1
- package/dist/lib/components/markdown.component.dom.test.js +40 -1
- package/dist/lib/components/markdown.component.dom.test.js.map +1 -1
- package/dist/lib/components/markdown.component.js +24 -4
- package/dist/lib/components/markdown.component.js.map +1 -1
- package/dist/lib/services/markdown.service.d.ts +38 -0
- package/dist/lib/services/markdown.service.d.ts.map +1 -1
- package/dist/lib/services/markdown.service.dom.test.js +149 -0
- package/dist/lib/services/markdown.service.dom.test.js.map +1 -1
- package/dist/lib/services/markdown.service.js +180 -4
- package/dist/lib/services/markdown.service.js.map +1 -1
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.component.js","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,MAAM,EACN,YAAY,EACZ,UAAU,EAIV,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAElB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAY,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAkB,uBAAuB,EAAoC,MAAM,+BAA+B,CAAC;;;;AAC1H,4EAA4E;AAE5E;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,MAAM,OAAO,iBAAiB;IAM5B,oCAAoC;IACpC,IAAa,IAAI,CAAC,KAAa;QAC7B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;IACpB,CAAC;IACD,oCAAoC;IACpC,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAOD,+CAA+C;IAC/C,IAAa,eAAe,CAAC,KAAc;QACzC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IACD,+CAA+C;IAC/C,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAOD,6CAA6C;IAC7C,IAAa,aAAa,CAAC,KAAc;QACvC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC7B,CAAC;IACD,6CAA6C;IAC7C,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAOD,8CAA8C;IAC9C,IAAa,cAAc,CAAC,KAAc;QACxC,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;IACD,8CAA8C;IAC9C,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAOD,yDAAyD;IACzD,IAAa,yBAAyB,CAAC,KAAc;QACnD,IAAI,CAAC,yBAAyB,GAAG,KAAK,CAAC;IACzC,CAAC;IACD,yDAAyD;IACzD,IAAI,yBAAyB;QAC3B,OAAO,IAAI,CAAC,yBAAyB,CAAC;IACxC,CAAC;IAOD,uDAAuD;IACvD,IAAa,uBAAuB,CAAC,KAA4B;QAC/D,IAAI,CAAC,uBAAuB,GAAG,KAAK,CAAC;IACvC,CAAC;IACD,uDAAuD;IACvD,IAAI,uBAAuB;QACzB,OAAO,IAAI,CAAC,uBAAuB,CAAC;IACtC,CAAC;IAOD,0DAA0D;IAC1D,IAAa,0BAA0B,CAAC,KAAc;QACpD,IAAI,CAAC,0BAA0B,GAAG,KAAK,CAAC;IAC1C,CAAC;IACD,0DAA0D;IAC1D,IAAI,0BAA0B;QAC5B,OAAO,IAAI,CAAC,0BAA0B,CAAC;IACzC,CAAC;IAeD,gDAAgD;IAChD,IAAa,gBAAgB,CAAC,KAA2B;QACvD,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IACD,gDAAgD;IAChD,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAOD,4CAA4C;IAC5C,IAAa,YAAY,CAAC,KAAc;QACtC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IACD,4CAA4C;IAC5C,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAOD,iDAAiD;IACjD,IAAa,iBAAiB,CAAC,KAAc;QAC3C,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;IACjC,CAAC;IACD,iDAAiD;IACjD,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAQD,iDAAiD;IACjD,IAAa,iBAAiB,CAAC,KAAc;QAC3C,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;IACjC,CAAC;IACD,iDAAiD;IACjD,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAQD,0CAA0C;IAC1C,IAAa,UAAU,CAAC,KAAc;QACpC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IACD,0CAA0C;IAC1C,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAQD,gDAAgD;IAChD,IAAa,gBAAgB,CAAC,KAAc;QAC1C,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IACD,gDAAgD;IAChD,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAOD,gDAAgD;IAChD,IAAa,gBAAgB,CAAC,KAAc;QAC1C,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IACD,gDAAgD;IAChD,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAOD,+CAA+C;IAC/C,IAAa,eAAe,CAAC,KAAa;QACxC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IACD,+CAA+C;IAC/C,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAOD,iDAAiD;IACjD,IAAa,iBAAiB,CAAC,KAAc;QAC3C,IAAI,CAAC,iBAAiB,GAAG,KAAK,CAAC;IACjC,CAAC;IACD,iDAAiD;IACjD,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAOD,8CAA8C;IAC9C,IAAa,cAAc,CAAC,KAAa;QACvC,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;IACD,8CAA8C;IAC9C,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAQD,4CAA4C;IAC5C,IAAa,YAAY,CAAC,KAAkE;QAC1F,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC5B,CAAC;IACD,4CAA4C;IAC5C,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAOD,wCAAwC;IACxC,IAAa,QAAQ,CAAC,KAAc;QAClC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,CAAC;IACD,wCAAwC;IACxC,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAiDD,+CAA+C;IAC/C,IAAW,eAAe;QACxB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IACD,+CAA+C;IAC/C,IAAW,eAAe,CAAC,KAAe;QACxC,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,uCAAuC;IACvC,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAOD,YACU,UAAmC,EACnC,SAAuB,EACvB,eAAgC,EAChC,GAAsB;QAHtB,eAAU,GAAV,UAAU,CAAyB;QACnC,cAAS,GAAT,SAAS,CAAc;QACvB,oBAAe,GAAf,eAAe,CAAiB;QAChC,QAAG,GAAH,GAAG,CAAmB;QApWhC;;WAEG;QACM,SAAI,GAAW,EAAE,CAAC;QAW3B;;WAEG;QACM,oBAAe,GAAY,uBAAuB,CAAC,eAAe,CAAC;QAW5E;;WAEG;QACM,kBAAa,GAAY,uBAAuB,CAAC,aAAa,CAAC;QAWxE;;WAEG;QACM,mBAAc,GAAY,uBAAuB,CAAC,cAAc,CAAC;QAW1E;;WAEG;QACM,8BAAyB,GAAY,uBAAuB,CAAC,yBAAyB,CAAC;QAWhG;;WAEG;QACM,4BAAuB,GAA0B,uBAAuB,CAAC,uBAAuB,CAAC;QAW1G;;WAEG;QACM,+BAA0B,GAAY,uBAAuB,CAAC,0BAA0B,CAAC;QAiClG;;WAEG;QACM,iBAAY,GAAY,uBAAuB,CAAC,YAAY,CAAC;QAWtE;;WAEG;QACM,sBAAiB,GAAY,uBAAuB,CAAC,iBAAiB,CAAC;QAWhF;;;WAGG;QACM,sBAAiB,GAAY,uBAAuB,CAAC,iBAAiB,CAAC;QAWhF;;;WAGG;QACM,eAAU,GAAY,uBAAuB,CAAC,UAAU,CAAC;QAWlE;;;WAGG;QACM,qBAAgB,GAAY,uBAAuB,CAAC,gBAAgB,CAAC;QAW9E;;WAEG;QACM,qBAAgB,GAAY,uBAAuB,CAAC,gBAAgB,CAAC;QAW9E;;WAEG;QACM,oBAAe,GAAW,uBAAuB,CAAC,eAAe,CAAC;QAW3E;;WAEG;QACM,sBAAiB,GAAY,uBAAuB,CAAC,iBAAiB,CAAC;QAWhF;;WAEG;QACM,mBAAc,GAAW,EAAE,CAAC;QAWrC;;;WAGG;QACM,iBAAY,GAAgE,uBAAuB,CAAC,YAAY,CAAC;QAW1H;;WAEG;QACM,aAAQ,GAAY,uBAAuB,CAAC,QAAQ,CAAC;QAW9D;;WAEG;QACO,aAAQ,GAAG,IAAI,YAAY,EAAuB,CAAC;QAE7D;;;;;;WAMG;QACO,aAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAEnC;;WAEG;QACO,iBAAY,GAAG,IAAI,YAAY,EAAe,CAAC;QAEzD;;;;;;WAMG;QACO,iBAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QAE3C;;WAEG;QACO,eAAU,GAAG,IAAI,YAAY,EAAU,CAAC;QAElD;;;;;;WAMG;QACO,eAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAEvC;;WAEG;QACI,oBAAe,GAAa,EAAE,CAAC;QAwB9B,oBAAe,GAAW,CAAC,CAAC;QAC5B,eAAU,GAAY,KAAK,CAAC;QAC5B,kBAAa,GAAY,KAAK,CAAC;QAC/B,kBAAa,GAA4B,IAAI,CAAC;IAOnD,CAAC;IAEJ,WAAW,CAAC,OAAsB;QAChC,sCAAsC;QACtC,MAAM,aAAa,GACjB,OAAO,CAAC,MAAM,CAAC;YACf,OAAO,CAAC,iBAAiB,CAAC;YAC1B,OAAO,CAAC,eAAe,CAAC;YACxB,OAAO,CAAC,gBAAgB,CAAC;YACzB,OAAO,CAAC,2BAA2B,CAAC;YACpC,OAAO,CAAC,yBAAyB,CAAC;YAClC,OAAO,CAAC,4BAA4B,CAAC;YACrC,OAAO,CAAC,kBAAkB,CAAC;YAC3B,OAAO,CAAC,cAAc,CAAC;YACvB,OAAO,CAAC,mBAAmB,CAAC;YAC5B,OAAO,CAAC,mBAAmB,CAAC;YAC5B,OAAO,CAAC,YAAY,CAAC;YACrB,OAAO,CAAC,kBAAkB,CAAC;YAC3B,OAAO,CAAC,kBAAkB,CAAC;YAC3B,OAAO,CAAC,iBAAiB,CAAC;YAC1B,OAAO,CAAC,cAAc,CAAC;YACvB,OAAO,CAAC,UAAU,CAAC,CAAC;QAEtB,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,eAAe;QACb,sCAAsC;QACtC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED,WAAW;QACT,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAED;;OAEG;IACK,MAAM;QACZ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAEzC,2BAA2B;QAC3B,MAAM,MAAM,GAAmB;YAC7B,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,yBAAyB,EAAE,IAAI,CAAC,yBAAyB;YACzD,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;YACrD,0BAA0B,EAAE,IAAI,CAAC,0BAA0B;YAC3D,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC;QAEF,8BAA8B;QAC9B,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEjD,oCAAoC;QACpC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QACxF,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEtE,sBAAsB;QACtB,uFAAuF;QACvF,4DAA4D;QAC5D,MAAM,sBAAsB,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,UAAU,CAAC;QACzE,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,sBAAsB,EAAE,CAAC;YAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACtE,IAAI,GAAG,SAAS,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,+EAA+E;QAC/E,mFAAmF;QACnF,yCAAyC;QAEzC,6BAA6B;QAC7B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAExB,mEAAmE;QACnE,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,oBAAoB;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;QACxF,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,kCAAkC;QAClC,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,SAAwB,CAAC,CAAC;QACpE,CAAC;QAED,kCAAkC;QAClC,IAAI,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACnC,IAAI,CAAC,eAAe,CAAC,6BAA6B,CAAC,SAAwB,CAAC,CAAC;YAC7E,IAAI,CAAC,yBAAyB,CAAC,SAAwB,CAAC,CAAC;QAC3D,CAAC;QAED,kCAAkC;QAClC,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,SAAwB,CAAC,CAAC;QACrE,CAAC;QAED,gCAAgC;QAChC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,IAAI,CAAC,0BAA0B,CAAC,SAAwB,CAAC,CAAC;QAC5D,CAAC;QAED,sDAAsD;QACtD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,sBAAsB,CAAC,SAAwB,CAAC,CAAC;QACxD,CAAC;QAED,sBAAsB;QACtB,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC;QAEzD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,IAAI,EAAG,SAAyB,CAAC,SAAS;YAC1C,UAAU;YACV,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,yBAAyB,CAAC,SAAsB;QACtD,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,CAAC;QAEpE,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,uCAAuC,CAAuB,CAAC;YACrG,IAAI,CAAC,OAAO;gBAAE,OAAO;YAErB,iCAAiC;YACjC,IAAI,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC;gBAAE,OAAO;YAEzD,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,sBAAsB,CAAC,KAAK,IAAI,CAAC;YAE3E,iCAAiC;YACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,GAAG,oBAAoB,CAAC;YACxC,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACrC,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;YACzD,MAAM,CAAC,SAAS,GAAG;;aAEZ,CAAC;YAER,+BAA+B;YAC/B,OAAO,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAEjD,sDAAsD;YACtD,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAsB,CAAC,CAAC;gBACjE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;YAED,mCAAmC;YACnC,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;YAEjC,4DAA4D;YAC5D,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE;gBAC7C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAqB,CAAC;gBACvC,6CAA6C;gBAC7C,IAAI,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC;oBAAE,OAAO;gBAEnD,CAAC,CAAC,cAAc,EAAE,CAAC;gBACnB,CAAC,CAAC,eAAe,EAAE,CAAC;gBACpB,IAAI,CAAC,aAAa,CAAC,OAAsB,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;YAEH,uBAAuB;YACvB,OAAO,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAQ,EAAE,EAAE;gBAC/C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAqB,CAAC;gBACvC,IAAI,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC;oBAAE,OAAO;gBAEnD,MAAM,QAAQ,GAAG,CAAkB,CAAC;gBACpC,IAAI,QAAQ,CAAC,GAAG,KAAK,OAAO,IAAI,QAAQ,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;oBACrD,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,IAAI,CAAC,aAAa,CAAC,OAAsB,EAAE,MAAM,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,OAAoB;QAC9C,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACjD,SAAS,CAAC,SAAS,GAAG,qBAAqB,CAAC;QAE5C,oBAAoB;QACpB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnD,SAAS,CAAC,SAAS,GAAG,mCAAmC,CAAC;QAC1D,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzC,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAC9C,SAAS,CAAC,SAAS,GAAG;;;WAGf,CAAC;QAER,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE;YAC/C,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,CAAC,CAAC,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAChC,8CAA8C;YAC9C,IAAI,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC5C,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;gBACtC,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,2DAA2D,CAAC,CAAC;gBAClG,IAAI,MAAM;oBAAE,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,sBAAsB;QACtB,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACrD,WAAW,CAAC,SAAS,GAAG,qCAAqC,CAAC;QAC9D,WAAW,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAClD,WAAW,CAAC,SAAS,GAAG;;;WAGjB,CAAC;QAER,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE;YACjD,CAAC,CAAC,cAAc,EAAE,CAAC;YACnB,CAAC,CAAC,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,SAAS,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACjC,SAAS,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAEnC,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACK,aAAa,CAAC,OAAoB,EAAE,MAAmB;QAC7D,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAE5D,qBAAqB;QACrB,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;QAC1D,2EAA2E;IAC7E,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,OAAoB;QAC9C,MAAM,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,CAAC;QACrE,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,2DAA2D,CAAC,CAAC;YAC/F,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;YAChD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,iBAAiB,CAAC,OAAoB;QAC5C,MAAM,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,CAAC;QACrE,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,2DAA2D,CAAC,CAAC;YAC/F,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,0BAA0B,CAAC,SAAsB;QACvD,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,CAAC,gDAAgD,CAAC,CAAC;QAE9F,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC3B,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBACrC,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAEtD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;oBACrB,EAAE;oBACF,IAAI;oBACJ,KAAK;oBACL,GAAG,EAAE,IAAI;iBACV,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,SAAsB;QACnD,MAAM,WAAW,GAAG,SAAS,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;QAEjE,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC7B,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBACpC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAClC,MAAM,IAAI,GAAG,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;gBACxC,IAAI,IAAI,EAAE,CAAC;oBACT,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACK,kBAAkB;QACxB,IAAI,OAAO,gBAAgB,KAAK,WAAW;YAAE,OAAO;QAEpD,IAAI,CAAC,aAAa,GAAG,IAAI,gBAAgB,CAAC,CAAC,SAAS,EAAE,EAAE;YACtD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,IAAI,QAAQ,CAAC,aAAa,KAAK,YAAY,EAAE,CAAC;oBAC9E,IAAI,CAAC,uBAAuB,EAAE,CAAC;oBAC/B,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE;YACnD,UAAU,EAAE,IAAI;YAChB,eAAe,EAAE,CAAC,YAAY,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,uBAAuB;QAC7B,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACvF,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,qBAAqB;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;QACxF,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,4CAA4C;QAC5C,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACxC,SAAS,CAAC,UAAU,EAAE,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC;IAED;;OAEG;IACI,OAAO;QACZ,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,uCAAuC;IAChC,OAAO;QACZ,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACI,WAAW;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC;IAC/C,CAAC;IAED,2CAA2C;IACpC,WAAW;QAChB,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACI,eAAe,CAAC,SAAiB;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;QACxF,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC;QACzD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,+CAA+C;IACxC,eAAe,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;kHArxBU,iBAAiB;oEAAjB,iBAAiB;YALhB,yBAAgG;;YAA7D,iCAAwB;YAAC,kEAA6B;;;iFAK1F,iBAAiB;cAR7B,SAAS;2BACE,aAAa,cACX,KAAK,YACP,oGAAoG,iBAE/F,iBAAiB,CAAC,IAAI,mBACpB,uBAAuB,CAAC,MAAM;;kBAM9C,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAmBL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAYL,KAAK;;kBAGL,KAAK;;kBAYL,KAAK;;kBAGL,KAAK;;kBAYL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAYL,KAAK;;kBAGL,KAAK;;kBAWL,KAAK;;kBAGL,KAAK;;kBAWL,MAAM;;kBASN,MAAM;;kBAKN,MAAM;;kBASN,MAAM;;kBAKN,MAAM;;kBASN,MAAM;;kFA/TI,iBAAiB","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ElementRef,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n SecurityContext,\n ViewEncapsulation,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n AfterViewInit,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { MarkdownService } from '../services/markdown.service';\nimport { MarkdownConfig, DEFAULT_MARKDOWN_CONFIG, MarkdownRenderEvent, HeadingInfo } from '@memberjunction/markdown-core';\n// Collapsible section toggle is handled inline in setupCollapsibleListeners\n\n/**\n * Angular component for rendering markdown content.\n *\n * Features:\n * - Prism.js syntax highlighting for code blocks\n * - Mermaid diagram rendering\n * - Copy-to-clipboard for code blocks\n * - Collapsible heading sections\n * - GitHub-style alerts and heading IDs\n *\n * Usage:\n * ```html\n * <mj-markdown [data]=\"markdownContent\"></mj-markdown>\n *\n * <mj-markdown\n * [data]=\"content\"\n * [enableMermaid]=\"true\"\n * [enableCollapsibleHeadings]=\"true\"\n * (rendered)=\"onRendered($event)\">\n * </mj-markdown>\n * ```\n */\n@Component({\n selector: 'mj-markdown',\n standalone: false,\n template: ` <div class=\"mj-markdown-container\" [class]=\"containerClass\" [innerHTML]=\"renderedContent\"></div> `,\n styleUrls: ['./markdown.component.css'],\n encapsulation: ViewEncapsulation.None, // Allow styles to penetrate into rendered content\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {\n /**\n * The markdown content to render\n */\n @Input() Data: string = '';\n\n /** @deprecated Use {@link Data}. */\n @Input() set data(value: string) {\n this.Data = value;\n }\n /** @deprecated Use {@link Data}. */\n get data(): string {\n return this.Data;\n }\n\n /**\n * Enable syntax highlighting\n */\n @Input() EnableHighlight: boolean = DEFAULT_MARKDOWN_CONFIG.enableHighlight;\n\n /** @deprecated Use {@link EnableHighlight}. */\n @Input() set enableHighlight(value: boolean) {\n this.EnableHighlight = value;\n }\n /** @deprecated Use {@link EnableHighlight}. */\n get enableHighlight(): boolean {\n return this.EnableHighlight;\n }\n\n /**\n * Enable Mermaid diagram rendering\n */\n @Input() EnableMermaid: boolean = DEFAULT_MARKDOWN_CONFIG.enableMermaid;\n\n /** @deprecated Use {@link EnableMermaid}. */\n @Input() set enableMermaid(value: boolean) {\n this.EnableMermaid = value;\n }\n /** @deprecated Use {@link EnableMermaid}. */\n get enableMermaid(): boolean {\n return this.EnableMermaid;\n }\n\n /**\n * Enable copy button on code blocks\n */\n @Input() EnableCodeCopy: boolean = DEFAULT_MARKDOWN_CONFIG.enableCodeCopy;\n\n /** @deprecated Use {@link EnableCodeCopy}. */\n @Input() set enableCodeCopy(value: boolean) {\n this.EnableCodeCopy = value;\n }\n /** @deprecated Use {@link EnableCodeCopy}. */\n get enableCodeCopy(): boolean {\n return this.EnableCodeCopy;\n }\n\n /**\n * Enable collapsible heading sections\n */\n @Input() EnableCollapsibleHeadings: boolean = DEFAULT_MARKDOWN_CONFIG.enableCollapsibleHeadings;\n\n /** @deprecated Use {@link EnableCollapsibleHeadings}. */\n @Input() set enableCollapsibleHeadings(value: boolean) {\n this.EnableCollapsibleHeadings = value;\n }\n /** @deprecated Use {@link EnableCollapsibleHeadings}. */\n get enableCollapsibleHeadings(): boolean {\n return this.EnableCollapsibleHeadings;\n }\n\n /**\n * Heading level at which to start collapsing\n */\n @Input() CollapsibleHeadingLevel: 1 | 2 | 3 | 4 | 5 | 6 = DEFAULT_MARKDOWN_CONFIG.collapsibleHeadingLevel;\n\n /** @deprecated Use {@link CollapsibleHeadingLevel}. */\n @Input() set collapsibleHeadingLevel(value: 1 | 2 | 3 | 4 | 5 | 6) {\n this.CollapsibleHeadingLevel = value;\n }\n /** @deprecated Use {@link CollapsibleHeadingLevel}. */\n get collapsibleHeadingLevel(): 1 | 2 | 3 | 4 | 5 | 6 {\n return this.CollapsibleHeadingLevel;\n }\n\n /**\n * Whether collapsible sections should be expanded by default\n */\n @Input() CollapsibleDefaultExpanded: boolean = DEFAULT_MARKDOWN_CONFIG.collapsibleDefaultExpanded;\n\n /** @deprecated Use {@link CollapsibleDefaultExpanded}. */\n @Input() set collapsibleDefaultExpanded(value: boolean) {\n this.CollapsibleDefaultExpanded = value;\n }\n /** @deprecated Use {@link CollapsibleDefaultExpanded}. */\n get collapsibleDefaultExpanded(): boolean {\n return this.CollapsibleDefaultExpanded;\n }\n\n /**\n * Specify which heading levels should start expanded.\n * Array of heading levels (2-6) that should be expanded by default.\n * Takes precedence over collapsibleDefaultExpanded for specified levels.\n *\n * Examples:\n * - [2] = Only h2 expanded, h3-h6 collapsed\n * - [2, 3] = h2 and h3 expanded, h4-h6 collapsed\n * - [] = All collapsed\n * - undefined = Uses collapsibleDefaultExpanded for all levels\n */\n @Input() AutoExpandLevels?: number[];\n\n /** @deprecated Use {@link AutoExpandLevels}. */\n @Input() set autoExpandLevels(value: number[] | undefined) {\n this.AutoExpandLevels = value;\n }\n /** @deprecated Use {@link AutoExpandLevels}. */\n get autoExpandLevels(): number[] | undefined {\n return this.AutoExpandLevels;\n }\n\n /**\n * Enable GitHub-style alerts\n */\n @Input() EnableAlerts: boolean = DEFAULT_MARKDOWN_CONFIG.enableAlerts;\n\n /** @deprecated Use {@link EnableAlerts}. */\n @Input() set enableAlerts(value: boolean) {\n this.EnableAlerts = value;\n }\n /** @deprecated Use {@link EnableAlerts}. */\n get enableAlerts(): boolean {\n return this.EnableAlerts;\n }\n\n /**\n * Enable smartypants for typography (curly quotes, em/en dashes, ellipses)\n */\n @Input() EnableSmartypants: boolean = DEFAULT_MARKDOWN_CONFIG.enableSmartypants;\n\n /** @deprecated Use {@link EnableSmartypants}. */\n @Input() set enableSmartypants(value: boolean) {\n this.EnableSmartypants = value;\n }\n /** @deprecated Use {@link EnableSmartypants}. */\n get enableSmartypants(): boolean {\n return this.EnableSmartypants;\n }\n\n /**\n * Enable SVG code block rendering\n * When enabled, ```svg code blocks are rendered as actual SVG images\n */\n @Input() EnableSvgRenderer: boolean = DEFAULT_MARKDOWN_CONFIG.enableSvgRenderer;\n\n /** @deprecated Use {@link EnableSvgRenderer}. */\n @Input() set enableSvgRenderer(value: boolean) {\n this.EnableSvgRenderer = value;\n }\n /** @deprecated Use {@link EnableSvgRenderer}. */\n get enableSvgRenderer(): boolean {\n return this.EnableSvgRenderer;\n }\n\n /**\n * Enable raw HTML passthrough in markdown content.\n * Scripts and event handlers are still stripped unless enableJavaScript is true.\n */\n @Input() EnableHtml: boolean = DEFAULT_MARKDOWN_CONFIG.enableHtml;\n\n /** @deprecated Use {@link EnableHtml}. */\n @Input() set enableHtml(value: boolean) {\n this.EnableHtml = value;\n }\n /** @deprecated Use {@link EnableHtml}. */\n get enableHtml(): boolean {\n return this.EnableHtml;\n }\n\n /**\n * Enable JavaScript in HTML content (<script> tags and on* handlers).\n * WARNING: Major security risk - only enable for fully trusted content.\n */\n @Input() EnableJavaScript: boolean = DEFAULT_MARKDOWN_CONFIG.enableJavaScript;\n\n /** @deprecated Use {@link EnableJavaScript}. */\n @Input() set enableJavaScript(value: boolean) {\n this.EnableJavaScript = value;\n }\n /** @deprecated Use {@link EnableJavaScript}. */\n get enableJavaScript(): boolean {\n return this.EnableJavaScript;\n }\n\n /**\n * Enable heading IDs for anchor links\n */\n @Input() EnableHeadingIds: boolean = DEFAULT_MARKDOWN_CONFIG.enableHeadingIds;\n\n /** @deprecated Use {@link EnableHeadingIds}. */\n @Input() set enableHeadingIds(value: boolean) {\n this.EnableHeadingIds = value;\n }\n /** @deprecated Use {@link EnableHeadingIds}. */\n get enableHeadingIds(): boolean {\n return this.EnableHeadingIds;\n }\n\n /**\n * Prefix for heading IDs\n */\n @Input() HeadingIdPrefix: string = DEFAULT_MARKDOWN_CONFIG.headingIdPrefix;\n\n /** @deprecated Use {@link HeadingIdPrefix}. */\n @Input() set headingIdPrefix(value: string) {\n this.HeadingIdPrefix = value;\n }\n /** @deprecated Use {@link HeadingIdPrefix}. */\n get headingIdPrefix(): string {\n return this.HeadingIdPrefix;\n }\n\n /**\n * Enable line numbers in code blocks\n */\n @Input() EnableLineNumbers: boolean = DEFAULT_MARKDOWN_CONFIG.enableLineNumbers;\n\n /** @deprecated Use {@link EnableLineNumbers}. */\n @Input() set enableLineNumbers(value: boolean) {\n this.EnableLineNumbers = value;\n }\n /** @deprecated Use {@link EnableLineNumbers}. */\n get enableLineNumbers(): boolean {\n return this.EnableLineNumbers;\n }\n\n /**\n * Custom CSS class for the container\n */\n @Input() ContainerClass: string = '';\n\n /** @deprecated Use {@link ContainerClass}. */\n @Input() set containerClass(value: string) {\n this.ContainerClass = value;\n }\n /** @deprecated Use {@link ContainerClass}. */\n get containerClass(): string {\n return this.ContainerClass;\n }\n\n /**\n * Mermaid theme.\n * 'auto' (default) detects light/dark from the document's data-theme attribute.\n */\n @Input() MermaidTheme: 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base' = DEFAULT_MARKDOWN_CONFIG.mermaidTheme;\n\n /** @deprecated Use {@link MermaidTheme}. */\n @Input() set mermaidTheme(value: 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base') {\n this.MermaidTheme = value;\n }\n /** @deprecated Use {@link MermaidTheme}. */\n get mermaidTheme(): 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base' {\n return this.MermaidTheme;\n }\n\n /**\n * Whether to sanitize HTML output\n */\n @Input() Sanitize: boolean = DEFAULT_MARKDOWN_CONFIG.sanitize;\n\n /** @deprecated Use {@link Sanitize}. */\n @Input() set sanitize(value: boolean) {\n this.Sanitize = value;\n }\n /** @deprecated Use {@link Sanitize}. */\n get sanitize(): boolean {\n return this.Sanitize;\n }\n\n /**\n * Emitted when rendering is complete\n */\n @Output() Rendered = new EventEmitter<MarkdownRenderEvent>();\n\n /**\n * @deprecated Use {@link Rendered}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (rendered) keeps working. Must stay AFTER Rendered: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() rendered = this.Rendered;\n\n /**\n * Emitted when a heading anchor is clicked\n */\n @Output() HeadingClick = new EventEmitter<HeadingInfo>();\n\n /**\n * @deprecated Use {@link HeadingClick}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (headingClick) keeps working. Must stay AFTER HeadingClick: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() headingClick = this.HeadingClick;\n\n /**\n * Emitted when code is copied to clipboard\n */\n @Output() CodeCopied = new EventEmitter<string>();\n\n /**\n * @deprecated Use {@link CodeCopied}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (codeCopied) keeps working. Must stay AFTER CodeCopied: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() codeCopied = this.CodeCopied;\n\n /**\n * The sanitized HTML content to display\n */\n public RenderedContent: SafeHtml = '';\n\n /** @deprecated Use {@link RenderedContent}. */\n public get renderedContent(): SafeHtml {\n return this.RenderedContent;\n }\n /** @deprecated Use {@link RenderedContent}. */\n public set renderedContent(value: SafeHtml) {\n this.RenderedContent = value;\n }\n\n /**\n * Public accessor for the component's element reference.\n * Provided for backward compatibility with ngx-markdown API.\n */\n public get Element(): ElementRef<HTMLElement> {\n return this.elementRef;\n }\n\n /** @deprecated Use {@link Element}. */\n public get element(): ElementRef<HTMLElement> {\n return this.Element;\n }\n\n private renderStartTime: number = 0;\n private hasMermaid: boolean = false;\n private hasCodeBlocks: boolean = false;\n private themeObserver: MutationObserver | null = null;\n\n constructor(\n private elementRef: ElementRef<HTMLElement>,\n private sanitizer: DomSanitizer,\n private markdownService: MarkdownService,\n private cdr: ChangeDetectorRef,\n ) {}\n\n ngOnChanges(changes: SimpleChanges): void {\n // Check if any relevant input changed\n const needsRerender =\n changes['data'] ||\n changes['enableHighlight'] ||\n changes['enableMermaid'] ||\n changes['enableCodeCopy'] ||\n changes['enableCollapsibleHeadings'] ||\n changes['collapsibleHeadingLevel'] ||\n changes['collapsibleDefaultExpanded'] ||\n changes['autoExpandLevels'] ||\n changes['enableAlerts'] ||\n changes['enableSmartypants'] ||\n changes['enableSvgRenderer'] ||\n changes['enableHtml'] ||\n changes['enableJavaScript'] ||\n changes['enableHeadingIds'] ||\n changes['headingIdPrefix'] ||\n changes['mermaidTheme'] ||\n changes['sanitize'];\n\n if (needsRerender) {\n this.render();\n }\n }\n\n ngAfterViewInit(): void {\n // Initial render if data was provided\n if (this.Data) {\n this.postRenderProcessing();\n }\n\n this.setupThemeObserver();\n }\n\n ngOnDestroy(): void {\n this.themeObserver?.disconnect();\n this.themeObserver = null;\n this.cleanupEventListeners();\n }\n\n /**\n * Render the markdown content\n */\n private render(): void {\n if (!this.Data) {\n this.RenderedContent = '';\n this.cdr.markForCheck();\n return;\n }\n\n this.renderStartTime = performance.now();\n\n // Build config from inputs\n const config: MarkdownConfig = {\n enableHighlight: this.EnableHighlight,\n enableMermaid: this.EnableMermaid,\n enableCodeCopy: this.EnableCodeCopy,\n enableCollapsibleHeadings: this.EnableCollapsibleHeadings,\n collapsibleHeadingLevel: this.CollapsibleHeadingLevel,\n collapsibleDefaultExpanded: this.CollapsibleDefaultExpanded,\n autoExpandLevels: this.AutoExpandLevels,\n enableAlerts: this.EnableAlerts,\n enableSmartypants: this.EnableSmartypants,\n enableSvgRenderer: this.EnableSvgRenderer,\n enableHtml: this.EnableHtml,\n enableJavaScript: this.EnableJavaScript,\n enableHeadingIds: this.EnableHeadingIds,\n headingIdPrefix: this.HeadingIdPrefix,\n mermaidTheme: this.MermaidTheme,\n sanitize: this.Sanitize,\n };\n\n // Configure service and parse\n this.markdownService.configureMarked(config);\n let html = this.markdownService.parse(this.Data);\n\n // Check for mermaid and code blocks\n this.hasMermaid = html.includes('language-mermaid') || html.includes('class=\"mermaid\"');\n this.hasCodeBlocks = html.includes('<pre>') && html.includes('<code');\n\n // Sanitize if enabled\n // Note: We bypass Angular's sanitizer when SVG renderer or HTML passthrough is enabled\n // because it strips SVG elements and most HTML layout tags.\n const bypassAngularSanitizer = this.EnableSvgRenderer || this.EnableHtml;\n if (this.Sanitize && !bypassAngularSanitizer) {\n const sanitized = this.sanitizer.sanitize(SecurityContext.HTML, html);\n html = sanitized || '';\n }\n\n // When Angular's sanitizer is bypassed, the HTML has already been sanitized by\n // MarkdownService.parse() (DOMPurify, HTML + SVG profiles) unless enableJavaScript\n // opted out. Nothing further to do here.\n\n // Trust the HTML for display\n this.RenderedContent = this.sanitizer.bypassSecurityTrustHtml(html);\n this.cdr.markForCheck();\n\n // Schedule post-render processing for next tick (after DOM update)\n Promise.resolve().then(() => this.postRenderProcessing());\n }\n\n /**\n * Process rendered content after DOM update\n * Handles syntax highlighting, mermaid rendering, copy buttons, etc.\n */\n private async postRenderProcessing(): Promise<void> {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Add copy buttons to code blocks\n if (this.EnableCodeCopy && this.hasCodeBlocks) {\n this.markdownService.addCodeCopyButtons(container as HTMLElement);\n }\n\n // Initialize collapsible headings\n if (this.EnableCollapsibleHeadings) {\n this.markdownService.initializeCollapsibleHeadings(container as HTMLElement);\n this.setupCollapsibleListeners(container as HTMLElement);\n }\n\n // Render mermaid diagrams (async)\n if (this.EnableMermaid && this.hasMermaid) {\n await this.markdownService.renderMermaid(container as HTMLElement);\n }\n\n // Setup heading click listeners\n if (this.EnableHeadingIds) {\n this.setupHeadingClickListeners(container as HTMLElement);\n }\n\n // Setup code copy listeners for custom event emission\n if (this.EnableCodeCopy) {\n this.setupCodeCopyListeners(container as HTMLElement);\n }\n\n // Emit rendered event\n const renderTime = performance.now() - this.renderStartTime;\n const headingIds = this.markdownService.getHeadingList();\n\n this.Rendered.emit({\n html: (container as HTMLElement).innerHTML,\n renderTime,\n hasMermaid: this.hasMermaid,\n hasCodeBlocks: this.hasCodeBlocks,\n headingIds,\n });\n }\n\n /**\n * Setup collapsible sections by adding toggle buttons and click listeners\n */\n private setupCollapsibleListeners(container: HTMLElement): void {\n const sections = container.querySelectorAll('.collapsible-section');\n\n sections.forEach((section) => {\n const wrapper = section.querySelector(':scope > .collapsible-heading-wrapper') as HTMLElement | null;\n if (!wrapper) return;\n\n // Check if toggle already exists\n if (wrapper.querySelector('.collapsible-toggle')) return;\n\n const isExpanded = !section.classList.contains('collapsed');\n const hasChildren = section.querySelector('.collapsible-section') !== null;\n\n // Create toggle button (chevron)\n const toggle = document.createElement('span');\n toggle.className = 'collapsible-toggle';\n toggle.setAttribute('role', 'button');\n toggle.setAttribute('tabindex', '0');\n toggle.setAttribute('aria-expanded', String(isExpanded));\n toggle.innerHTML = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M6 12l4-4-4-4\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n // Insert toggle before heading\n wrapper.insertBefore(toggle, wrapper.firstChild);\n\n // Add action buttons container (only if has children)\n if (hasChildren) {\n const actions = this.createActionButtons(section as HTMLElement);\n wrapper.appendChild(actions);\n }\n\n // Make the whole wrapper clickable\n wrapper.style.cursor = 'pointer';\n\n // Add click listener to wrapper (but not on action buttons)\n wrapper.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n // Don't toggle if clicking on action buttons\n if (target.closest('.collapsible-actions')) return;\n\n e.preventDefault();\n e.stopPropagation();\n this.toggleSection(section as HTMLElement, toggle);\n });\n\n // Add keyboard support\n wrapper.addEventListener('keydown', (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.closest('.collapsible-actions')) return;\n\n const keyEvent = e as KeyboardEvent;\n if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {\n e.preventDefault();\n this.toggleSection(section as HTMLElement, toggle);\n }\n });\n });\n }\n\n /**\n * Create the expand/collapse all action buttons for sections with children\n */\n private createActionButtons(section: HTMLElement): HTMLElement {\n const container = document.createElement('span');\n container.className = 'collapsible-actions';\n\n // Expand all button\n const expandBtn = document.createElement('button');\n expandBtn.className = 'collapsible-action-btn expand-all';\n expandBtn.setAttribute('type', 'button');\n expandBtn.setAttribute('title', 'Expand all');\n expandBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 6l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 10l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n expandBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.expandDescendants(section);\n // Also expand the section itself if collapsed\n if (section.classList.contains('collapsed')) {\n section.classList.remove('collapsed');\n const toggle = section.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) toggle.setAttribute('aria-expanded', 'true');\n }\n });\n\n // Collapse all button\n const collapseBtn = document.createElement('button');\n collapseBtn.className = 'collapsible-action-btn collapse-all';\n collapseBtn.setAttribute('type', 'button');\n collapseBtn.setAttribute('title', 'Collapse all');\n collapseBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 10l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 14l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n collapseBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.collapseDescendants(section);\n });\n\n container.appendChild(expandBtn);\n container.appendChild(collapseBtn);\n\n return container;\n }\n\n /**\n * Toggle a collapsible section\n * @param section The section element to toggle\n * @param toggle The toggle button element\n */\n private toggleSection(section: HTMLElement, toggle: HTMLElement): void {\n const isCollapsed = section.classList.contains('collapsed');\n\n // Toggle the section\n section.classList.toggle('collapsed');\n toggle.setAttribute('aria-expanded', String(isCollapsed));\n // Children retain their state - CSS handles visibility via parent collapse\n }\n\n /**\n * Collapse all descendant sections (used by action button)\n */\n private collapseDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.add('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'false');\n }\n });\n }\n\n /**\n * Expand all descendant sections (used by action button)\n */\n private expandDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.remove('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'true');\n }\n });\n }\n\n /**\n * Setup click listeners for heading anchors\n */\n private setupHeadingClickListeners(container: HTMLElement): void {\n const headings = container.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]');\n\n headings.forEach((heading) => {\n heading.addEventListener('click', () => {\n const id = heading.getAttribute('id') || '';\n const text = heading.textContent || '';\n const level = parseInt(heading.tagName.charAt(1), 10);\n\n this.HeadingClick.emit({\n id,\n text,\n level,\n raw: text,\n });\n });\n });\n }\n\n /**\n * Setup listeners to emit code copy events\n */\n private setupCodeCopyListeners(container: HTMLElement): void {\n const copyButtons = container.querySelectorAll('.code-copy-btn');\n\n copyButtons.forEach((button) => {\n button.addEventListener('click', () => {\n const pre = button.closest('pre');\n const code = pre?.querySelector('code');\n if (code) {\n this.CodeCopied.emit(code.textContent || '');\n }\n });\n });\n }\n\n /**\n * Watch the document's data-theme attribute for changes.\n * When the app theme switches (light ↔ dark) and mermaidTheme is 'auto',\n * re-render so mermaid diagrams pick up the new theme.\n */\n private setupThemeObserver(): void {\n if (typeof MutationObserver === 'undefined') return;\n\n this.themeObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {\n this.onThemeAttributeChanged();\n break;\n }\n }\n });\n\n this.themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme'],\n });\n }\n\n /**\n * Called when data-theme changes on the document root.\n * Triggers a full re-render when mermaid auto-theming is active.\n */\n private onThemeAttributeChanged(): void {\n if (this.MermaidTheme === 'auto' && this.EnableMermaid && this.hasMermaid && this.Data) {\n this.render();\n }\n }\n\n /**\n * Cleanup event listeners\n */\n private cleanupEventListeners(): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Clone and replace to remove all listeners\n const clone = container.cloneNode(true);\n container.parentNode?.replaceChild(clone, container);\n }\n\n /**\n * Force a re-render of the markdown content\n */\n public Refresh(): void {\n this.render();\n }\n\n /** @deprecated Use {@link Refresh}. */\n public refresh(): void {\n return this.Refresh();\n }\n\n /**\n * Get the current heading list (for TOC building)\n */\n public GetHeadings(): HeadingInfo[] {\n return this.markdownService.getHeadingList();\n }\n\n /** @deprecated Use {@link GetHeadings}. */\n public getHeadings(): HeadingInfo[] {\n return this.GetHeadings();\n }\n\n /**\n * Scroll to a heading by ID\n */\n public ScrollToHeading(headingId: string): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n const heading = container.querySelector(`#${headingId}`);\n if (heading) {\n heading.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }\n\n /** @deprecated Use {@link ScrollToHeading}. */\n public scrollToHeading(headingId: string): void {\n return this.ScrollToHeading(headingId);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"markdown.component.js","sourceRoot":"","sources":["../../../src/lib/components/markdown.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ElementRef,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n SecurityContext,\n ViewEncapsulation,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n AfterViewInit,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { MarkdownService } from '../services/markdown.service';\nimport { MarkdownConfig, DEFAULT_MARKDOWN_CONFIG, MarkdownRenderEvent, HeadingInfo } from '@memberjunction/markdown-core';\n// Collapsible section toggle is handled inline in setupCollapsibleListeners\n\n/**\n * Angular component for rendering markdown content.\n *\n * Features:\n * - Prism.js syntax highlighting for code blocks\n * - Mermaid diagram rendering\n * - Copy-to-clipboard for code blocks\n * - Collapsible heading sections\n * - GitHub-style alerts and heading IDs\n *\n * Usage:\n * ```html\n * <mj-markdown [data]=\"markdownContent\"></mj-markdown>\n *\n * <mj-markdown\n * [data]=\"content\"\n * [enableMermaid]=\"true\"\n * [enableCollapsibleHeadings]=\"true\"\n * (rendered)=\"onRendered($event)\">\n * </mj-markdown>\n * ```\n */\n@Component({\n selector: 'mj-markdown',\n standalone: false,\n template: ` <div class=\"mj-markdown-container\" [class]=\"containerClass\" [innerHTML]=\"renderedContent\"></div> `,\n styleUrls: ['./markdown.component.css'],\n encapsulation: ViewEncapsulation.None, // Allow styles to penetrate into rendered content\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class MarkdownComponent implements OnChanges, AfterViewInit, OnDestroy {\n /**\n * The markdown content to render\n */\n @Input() Data: string = '';\n\n /** @deprecated Use {@link Data}. */\n @Input() set data(value: string) {\n this.Data = value;\n }\n /** @deprecated Use {@link Data}. */\n get data(): string {\n return this.Data;\n }\n\n /**\n * Enable syntax highlighting\n */\n @Input() EnableHighlight: boolean = DEFAULT_MARKDOWN_CONFIG.enableHighlight;\n\n /** @deprecated Use {@link EnableHighlight}. */\n @Input() set enableHighlight(value: boolean) {\n this.EnableHighlight = value;\n }\n /** @deprecated Use {@link EnableHighlight}. */\n get enableHighlight(): boolean {\n return this.EnableHighlight;\n }\n\n /**\n * Enable Mermaid diagram rendering\n */\n @Input() EnableMermaid: boolean = DEFAULT_MARKDOWN_CONFIG.enableMermaid;\n\n /** @deprecated Use {@link EnableMermaid}. */\n @Input() set enableMermaid(value: boolean) {\n this.EnableMermaid = value;\n }\n /** @deprecated Use {@link EnableMermaid}. */\n get enableMermaid(): boolean {\n return this.EnableMermaid;\n }\n\n /**\n * Enable TeX math (`$…$`, `$$…$$`, `\\(…\\)`, `\\[…\\]`), typeset as MathML\n */\n @Input() EnableMath: boolean = DEFAULT_MARKDOWN_CONFIG.enableMath;\n\n /**\n * Enable copy button on code blocks\n */\n @Input() EnableCodeCopy: boolean = DEFAULT_MARKDOWN_CONFIG.enableCodeCopy;\n\n /** @deprecated Use {@link EnableCodeCopy}. */\n @Input() set enableCodeCopy(value: boolean) {\n this.EnableCodeCopy = value;\n }\n /** @deprecated Use {@link EnableCodeCopy}. */\n get enableCodeCopy(): boolean {\n return this.EnableCodeCopy;\n }\n\n /**\n * Enable collapsible heading sections\n */\n @Input() EnableCollapsibleHeadings: boolean = DEFAULT_MARKDOWN_CONFIG.enableCollapsibleHeadings;\n\n /** @deprecated Use {@link EnableCollapsibleHeadings}. */\n @Input() set enableCollapsibleHeadings(value: boolean) {\n this.EnableCollapsibleHeadings = value;\n }\n /** @deprecated Use {@link EnableCollapsibleHeadings}. */\n get enableCollapsibleHeadings(): boolean {\n return this.EnableCollapsibleHeadings;\n }\n\n /**\n * Heading level at which to start collapsing\n */\n @Input() CollapsibleHeadingLevel: 1 | 2 | 3 | 4 | 5 | 6 = DEFAULT_MARKDOWN_CONFIG.collapsibleHeadingLevel;\n\n /** @deprecated Use {@link CollapsibleHeadingLevel}. */\n @Input() set collapsibleHeadingLevel(value: 1 | 2 | 3 | 4 | 5 | 6) {\n this.CollapsibleHeadingLevel = value;\n }\n /** @deprecated Use {@link CollapsibleHeadingLevel}. */\n get collapsibleHeadingLevel(): 1 | 2 | 3 | 4 | 5 | 6 {\n return this.CollapsibleHeadingLevel;\n }\n\n /**\n * Whether collapsible sections should be expanded by default\n */\n @Input() CollapsibleDefaultExpanded: boolean = DEFAULT_MARKDOWN_CONFIG.collapsibleDefaultExpanded;\n\n /** @deprecated Use {@link CollapsibleDefaultExpanded}. */\n @Input() set collapsibleDefaultExpanded(value: boolean) {\n this.CollapsibleDefaultExpanded = value;\n }\n /** @deprecated Use {@link CollapsibleDefaultExpanded}. */\n get collapsibleDefaultExpanded(): boolean {\n return this.CollapsibleDefaultExpanded;\n }\n\n /**\n * Specify which heading levels should start expanded.\n * Array of heading levels (2-6) that should be expanded by default.\n * Takes precedence over collapsibleDefaultExpanded for specified levels.\n *\n * Examples:\n * - [2] = Only h2 expanded, h3-h6 collapsed\n * - [2, 3] = h2 and h3 expanded, h4-h6 collapsed\n * - [] = All collapsed\n * - undefined = Uses collapsibleDefaultExpanded for all levels\n */\n @Input() AutoExpandLevels?: number[];\n\n /** @deprecated Use {@link AutoExpandLevels}. */\n @Input() set autoExpandLevels(value: number[] | undefined) {\n this.AutoExpandLevels = value;\n }\n /** @deprecated Use {@link AutoExpandLevels}. */\n get autoExpandLevels(): number[] | undefined {\n return this.AutoExpandLevels;\n }\n\n /**\n * Enable GitHub-style alerts\n */\n @Input() EnableAlerts: boolean = DEFAULT_MARKDOWN_CONFIG.enableAlerts;\n\n /** @deprecated Use {@link EnableAlerts}. */\n @Input() set enableAlerts(value: boolean) {\n this.EnableAlerts = value;\n }\n /** @deprecated Use {@link EnableAlerts}. */\n get enableAlerts(): boolean {\n return this.EnableAlerts;\n }\n\n /**\n * Enable smartypants for typography (curly quotes, em/en dashes, ellipses)\n */\n @Input() EnableSmartypants: boolean = DEFAULT_MARKDOWN_CONFIG.enableSmartypants;\n\n /** @deprecated Use {@link EnableSmartypants}. */\n @Input() set enableSmartypants(value: boolean) {\n this.EnableSmartypants = value;\n }\n /** @deprecated Use {@link EnableSmartypants}. */\n get enableSmartypants(): boolean {\n return this.EnableSmartypants;\n }\n\n /**\n * Enable SVG code block rendering\n * When enabled, ```svg code blocks are rendered as actual SVG images\n */\n @Input() EnableSvgRenderer: boolean = DEFAULT_MARKDOWN_CONFIG.enableSvgRenderer;\n\n /** @deprecated Use {@link EnableSvgRenderer}. */\n @Input() set enableSvgRenderer(value: boolean) {\n this.EnableSvgRenderer = value;\n }\n /** @deprecated Use {@link EnableSvgRenderer}. */\n get enableSvgRenderer(): boolean {\n return this.EnableSvgRenderer;\n }\n\n /**\n * Enable raw HTML passthrough in markdown content.\n * Scripts and event handlers are still stripped unless enableJavaScript is true.\n */\n @Input() EnableHtml: boolean = DEFAULT_MARKDOWN_CONFIG.enableHtml;\n\n /** @deprecated Use {@link EnableHtml}. */\n @Input() set enableHtml(value: boolean) {\n this.EnableHtml = value;\n }\n /** @deprecated Use {@link EnableHtml}. */\n get enableHtml(): boolean {\n return this.EnableHtml;\n }\n\n /**\n * Enable JavaScript in HTML content (<script> tags and on* handlers).\n * WARNING: Major security risk - only enable for fully trusted content.\n */\n @Input() EnableJavaScript: boolean = DEFAULT_MARKDOWN_CONFIG.enableJavaScript;\n\n /** @deprecated Use {@link EnableJavaScript}. */\n @Input() set enableJavaScript(value: boolean) {\n this.EnableJavaScript = value;\n }\n /** @deprecated Use {@link EnableJavaScript}. */\n get enableJavaScript(): boolean {\n return this.EnableJavaScript;\n }\n\n /**\n * Enable heading IDs for anchor links\n */\n @Input() EnableHeadingIds: boolean = DEFAULT_MARKDOWN_CONFIG.enableHeadingIds;\n\n /** @deprecated Use {@link EnableHeadingIds}. */\n @Input() set enableHeadingIds(value: boolean) {\n this.EnableHeadingIds = value;\n }\n /** @deprecated Use {@link EnableHeadingIds}. */\n get enableHeadingIds(): boolean {\n return this.EnableHeadingIds;\n }\n\n /**\n * Prefix for heading IDs\n */\n @Input() HeadingIdPrefix: string = DEFAULT_MARKDOWN_CONFIG.headingIdPrefix;\n\n /** @deprecated Use {@link HeadingIdPrefix}. */\n @Input() set headingIdPrefix(value: string) {\n this.HeadingIdPrefix = value;\n }\n /** @deprecated Use {@link HeadingIdPrefix}. */\n get headingIdPrefix(): string {\n return this.HeadingIdPrefix;\n }\n\n /**\n * Enable line numbers in code blocks\n */\n @Input() EnableLineNumbers: boolean = DEFAULT_MARKDOWN_CONFIG.enableLineNumbers;\n\n /** @deprecated Use {@link EnableLineNumbers}. */\n @Input() set enableLineNumbers(value: boolean) {\n this.EnableLineNumbers = value;\n }\n /** @deprecated Use {@link EnableLineNumbers}. */\n get enableLineNumbers(): boolean {\n return this.EnableLineNumbers;\n }\n\n /**\n * Custom CSS class for the container\n */\n @Input() ContainerClass: string = '';\n\n /** @deprecated Use {@link ContainerClass}. */\n @Input() set containerClass(value: string) {\n this.ContainerClass = value;\n }\n /** @deprecated Use {@link ContainerClass}. */\n get containerClass(): string {\n return this.ContainerClass;\n }\n\n /**\n * Mermaid theme.\n * 'auto' (default) detects light/dark from the document's data-theme attribute.\n */\n @Input() MermaidTheme: 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base' = DEFAULT_MARKDOWN_CONFIG.mermaidTheme;\n\n /** @deprecated Use {@link MermaidTheme}. */\n @Input() set mermaidTheme(value: 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base') {\n this.MermaidTheme = value;\n }\n /** @deprecated Use {@link MermaidTheme}. */\n get mermaidTheme(): 'auto' | 'default' | 'dark' | 'forest' | 'neutral' | 'base' {\n return this.MermaidTheme;\n }\n\n /**\n * Whether to sanitize HTML output\n */\n @Input() Sanitize: boolean = DEFAULT_MARKDOWN_CONFIG.sanitize;\n\n /** @deprecated Use {@link Sanitize}. */\n @Input() set sanitize(value: boolean) {\n this.Sanitize = value;\n }\n /** @deprecated Use {@link Sanitize}. */\n get sanitize(): boolean {\n return this.Sanitize;\n }\n\n /**\n * Emitted when rendering is complete\n */\n @Output() Rendered = new EventEmitter<MarkdownRenderEvent>();\n\n /**\n * @deprecated Use {@link Rendered}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (rendered) keeps working. Must stay AFTER Rendered: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() rendered = this.Rendered;\n\n /**\n * Emitted when a heading anchor is clicked\n */\n @Output() HeadingClick = new EventEmitter<HeadingInfo>();\n\n /**\n * @deprecated Use {@link HeadingClick}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (headingClick) keeps working. Must stay AFTER HeadingClick: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() headingClick = this.HeadingClick;\n\n /**\n * Emitted when code is copied to clipboard\n */\n @Output() CodeCopied = new EventEmitter<string>();\n\n /**\n * @deprecated Use {@link CodeCopied}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (codeCopied) keeps working. Must stay AFTER CodeCopied: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() codeCopied = this.CodeCopied;\n\n /**\n * The sanitized HTML content to display\n */\n public RenderedContent: SafeHtml = '';\n\n /** @deprecated Use {@link RenderedContent}. */\n public get renderedContent(): SafeHtml {\n return this.RenderedContent;\n }\n /** @deprecated Use {@link RenderedContent}. */\n public set renderedContent(value: SafeHtml) {\n this.RenderedContent = value;\n }\n\n /**\n * Public accessor for the component's element reference.\n * Provided for backward compatibility with ngx-markdown API.\n */\n public get Element(): ElementRef<HTMLElement> {\n return this.elementRef;\n }\n\n /** @deprecated Use {@link Element}. */\n public get element(): ElementRef<HTMLElement> {\n return this.Element;\n }\n\n private renderStartTime: number = 0;\n private hasMermaid: boolean = false;\n private hasMath: boolean = false;\n private hasCodeBlocks: boolean = false;\n private themeObserver: MutationObserver | null = null;\n\n constructor(\n private elementRef: ElementRef<HTMLElement>,\n private sanitizer: DomSanitizer,\n private markdownService: MarkdownService,\n private cdr: ChangeDetectorRef,\n ) {}\n\n ngOnChanges(changes: SimpleChanges): void {\n // Check if any relevant input changed\n const needsRerender =\n changes['data'] ||\n changes['enableHighlight'] ||\n changes['enableMermaid'] ||\n changes['EnableMath'] ||\n changes['enableCodeCopy'] ||\n changes['enableCollapsibleHeadings'] ||\n changes['collapsibleHeadingLevel'] ||\n changes['collapsibleDefaultExpanded'] ||\n changes['autoExpandLevels'] ||\n changes['enableAlerts'] ||\n changes['enableSmartypants'] ||\n changes['enableSvgRenderer'] ||\n changes['enableHtml'] ||\n changes['enableJavaScript'] ||\n changes['enableHeadingIds'] ||\n changes['headingIdPrefix'] ||\n changes['mermaidTheme'] ||\n changes['sanitize'];\n\n if (needsRerender) {\n this.render();\n }\n }\n\n ngAfterViewInit(): void {\n // Initial render if data was provided\n if (this.Data) {\n this.postRenderProcessing();\n }\n\n this.setupThemeObserver();\n }\n\n ngOnDestroy(): void {\n this.themeObserver?.disconnect();\n this.themeObserver = null;\n this.cleanupEventListeners();\n }\n\n /**\n * Render the markdown content\n */\n private render(): void {\n if (!this.Data) {\n this.RenderedContent = '';\n this.cdr.markForCheck();\n return;\n }\n\n this.renderStartTime = performance.now();\n\n // Build config from inputs\n const config: MarkdownConfig = {\n enableHighlight: this.EnableHighlight,\n enableMermaid: this.EnableMermaid,\n enableMath: this.EnableMath,\n enableCodeCopy: this.EnableCodeCopy,\n enableCollapsibleHeadings: this.EnableCollapsibleHeadings,\n collapsibleHeadingLevel: this.CollapsibleHeadingLevel,\n collapsibleDefaultExpanded: this.CollapsibleDefaultExpanded,\n autoExpandLevels: this.AutoExpandLevels,\n enableAlerts: this.EnableAlerts,\n enableSmartypants: this.EnableSmartypants,\n enableSvgRenderer: this.EnableSvgRenderer,\n enableHtml: this.EnableHtml,\n enableJavaScript: this.EnableJavaScript,\n enableHeadingIds: this.EnableHeadingIds,\n headingIdPrefix: this.HeadingIdPrefix,\n mermaidTheme: this.MermaidTheme,\n sanitize: this.Sanitize,\n };\n\n // Configure service and parse\n this.markdownService.configureMarked(config);\n let html = this.markdownService.parse(this.Data);\n\n // Check for mermaid and code blocks\n this.hasMermaid = html.includes('language-mermaid') || html.includes('class=\"mermaid\"');\n this.hasCodeBlocks = html.includes('<pre>') && html.includes('<code');\n this.hasMath = html.includes('class=\"mj-math') || html.includes('<math');\n\n // Sanitize if enabled\n // Note: We bypass Angular's sanitizer when SVG renderer or HTML passthrough is enabled\n // because it strips SVG elements and most HTML layout tags.\n const bypassAngularSanitizer = this.EnableSvgRenderer || this.EnableHtml;\n if (this.Sanitize && !bypassAngularSanitizer) {\n const sanitized = this.sanitizer.sanitize(SecurityContext.HTML, html);\n html = sanitized || '';\n }\n\n // When Angular's sanitizer is bypassed, the HTML has already been sanitized by\n // MarkdownService.parse() (DOMPurify, HTML, SVG and MathML profiles) unless enableJavaScript\n // opted out. Nothing further to do here.\n\n // Trust the HTML for display\n this.RenderedContent = this.sanitizer.bypassSecurityTrustHtml(html);\n this.cdr.markForCheck();\n\n // Schedule post-render processing for next tick (after DOM update)\n Promise.resolve().then(() => this.postRenderProcessing());\n }\n\n /**\n * Process rendered content after DOM update\n * Handles syntax highlighting, mermaid rendering, copy buttons, etc.\n */\n private async postRenderProcessing(): Promise<void> {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Add copy buttons to code blocks\n if (this.EnableCodeCopy && this.hasCodeBlocks) {\n this.markdownService.addCodeCopyButtons(container as HTMLElement);\n }\n\n // Initialize collapsible headings\n if (this.EnableCollapsibleHeadings) {\n this.markdownService.initializeCollapsibleHeadings(container as HTMLElement);\n this.setupCollapsibleListeners(container as HTMLElement);\n }\n\n // Typeset TeX math (async: KaTeX loads on first use). With math off, MathML that arrived as\n // markup still renders, so it still gets the styled-letter fix.\n if (this.hasMath) {\n if (this.EnableMath) {\n await this.markdownService.RenderMath(container as HTMLElement);\n } else {\n this.markdownService.UseUnicodeMathLetters(container as HTMLElement);\n }\n }\n\n // Render mermaid diagrams (async)\n if (this.EnableMermaid && this.hasMermaid) {\n await this.markdownService.renderMermaid(container as HTMLElement);\n }\n\n // Setup heading click listeners\n if (this.EnableHeadingIds) {\n this.setupHeadingClickListeners(container as HTMLElement);\n }\n\n // Setup code copy listeners for custom event emission\n if (this.EnableCodeCopy) {\n this.setupCodeCopyListeners(container as HTMLElement);\n }\n\n // Emit rendered event\n const renderTime = performance.now() - this.renderStartTime;\n const headingIds = this.markdownService.getHeadingList();\n\n this.Rendered.emit({\n html: (container as HTMLElement).innerHTML,\n renderTime,\n hasMermaid: this.hasMermaid,\n hasCodeBlocks: this.hasCodeBlocks,\n headingIds,\n });\n }\n\n /**\n * Setup collapsible sections by adding toggle buttons and click listeners\n */\n private setupCollapsibleListeners(container: HTMLElement): void {\n const sections = container.querySelectorAll('.collapsible-section');\n\n sections.forEach((section) => {\n const wrapper = section.querySelector(':scope > .collapsible-heading-wrapper') as HTMLElement | null;\n if (!wrapper) return;\n\n // Check if toggle already exists\n if (wrapper.querySelector('.collapsible-toggle')) return;\n\n const isExpanded = !section.classList.contains('collapsed');\n const hasChildren = section.querySelector('.collapsible-section') !== null;\n\n // Create toggle button (chevron)\n const toggle = document.createElement('span');\n toggle.className = 'collapsible-toggle';\n toggle.setAttribute('role', 'button');\n toggle.setAttribute('tabindex', '0');\n toggle.setAttribute('aria-expanded', String(isExpanded));\n toggle.innerHTML = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\n <path d=\"M6 12l4-4-4-4\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n // Insert toggle before heading\n wrapper.insertBefore(toggle, wrapper.firstChild);\n\n // Add action buttons container (only if has children)\n if (hasChildren) {\n const actions = this.createActionButtons(section as HTMLElement);\n wrapper.appendChild(actions);\n }\n\n // Make the whole wrapper clickable\n wrapper.style.cursor = 'pointer';\n\n // Add click listener to wrapper (but not on action buttons)\n wrapper.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n // Don't toggle if clicking on action buttons\n if (target.closest('.collapsible-actions')) return;\n\n e.preventDefault();\n e.stopPropagation();\n this.toggleSection(section as HTMLElement, toggle);\n });\n\n // Add keyboard support\n wrapper.addEventListener('keydown', (e: Event) => {\n const target = e.target as HTMLElement;\n if (target.closest('.collapsible-actions')) return;\n\n const keyEvent = e as KeyboardEvent;\n if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {\n e.preventDefault();\n this.toggleSection(section as HTMLElement, toggle);\n }\n });\n });\n }\n\n /**\n * Create the expand/collapse all action buttons for sections with children\n */\n private createActionButtons(section: HTMLElement): HTMLElement {\n const container = document.createElement('span');\n container.className = 'collapsible-actions';\n\n // Expand all button\n const expandBtn = document.createElement('button');\n expandBtn.className = 'collapsible-action-btn expand-all';\n expandBtn.setAttribute('type', 'button');\n expandBtn.setAttribute('title', 'Expand all');\n expandBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 6l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 10l4 4 4-4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n expandBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.expandDescendants(section);\n // Also expand the section itself if collapsed\n if (section.classList.contains('collapsed')) {\n section.classList.remove('collapsed');\n const toggle = section.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) toggle.setAttribute('aria-expanded', 'true');\n }\n });\n\n // Collapse all button\n const collapseBtn = document.createElement('button');\n collapseBtn.className = 'collapsible-action-btn collapse-all';\n collapseBtn.setAttribute('type', 'button');\n collapseBtn.setAttribute('title', 'Collapse all');\n collapseBtn.innerHTML = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 10l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n <path d=\"M4 14l4-4 4 4\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>`;\n\n collapseBtn.addEventListener('click', (e: Event) => {\n e.preventDefault();\n e.stopPropagation();\n this.collapseDescendants(section);\n });\n\n container.appendChild(expandBtn);\n container.appendChild(collapseBtn);\n\n return container;\n }\n\n /**\n * Toggle a collapsible section\n * @param section The section element to toggle\n * @param toggle The toggle button element\n */\n private toggleSection(section: HTMLElement, toggle: HTMLElement): void {\n const isCollapsed = section.classList.contains('collapsed');\n\n // Toggle the section\n section.classList.toggle('collapsed');\n toggle.setAttribute('aria-expanded', String(isCollapsed));\n // Children retain their state - CSS handles visibility via parent collapse\n }\n\n /**\n * Collapse all descendant sections (used by action button)\n */\n private collapseDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.add('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'false');\n }\n });\n }\n\n /**\n * Expand all descendant sections (used by action button)\n */\n private expandDescendants(section: HTMLElement): void {\n const descendants = section.querySelectorAll('.collapsible-section');\n descendants.forEach((desc) => {\n desc.classList.remove('collapsed');\n const toggle = desc.querySelector(':scope > .collapsible-heading-wrapper .collapsible-toggle');\n if (toggle) {\n toggle.setAttribute('aria-expanded', 'true');\n }\n });\n }\n\n /**\n * Setup click listeners for heading anchors\n */\n private setupHeadingClickListeners(container: HTMLElement): void {\n const headings = container.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]');\n\n headings.forEach((heading) => {\n heading.addEventListener('click', () => {\n const id = heading.getAttribute('id') || '';\n const text = heading.textContent || '';\n const level = parseInt(heading.tagName.charAt(1), 10);\n\n this.HeadingClick.emit({\n id,\n text,\n level,\n raw: text,\n });\n });\n });\n }\n\n /**\n * Setup listeners to emit code copy events\n */\n private setupCodeCopyListeners(container: HTMLElement): void {\n const copyButtons = container.querySelectorAll('.code-copy-btn');\n\n copyButtons.forEach((button) => {\n button.addEventListener('click', () => {\n const pre = button.closest('pre');\n const code = pre?.querySelector('code');\n if (code) {\n this.CodeCopied.emit(code.textContent || '');\n }\n });\n });\n }\n\n /**\n * Watch the document's data-theme attribute for changes.\n * When the app theme switches (light ↔ dark) and mermaidTheme is 'auto',\n * re-render so mermaid diagrams pick up the new theme.\n */\n private setupThemeObserver(): void {\n if (typeof MutationObserver === 'undefined') return;\n\n this.themeObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-theme') {\n this.onThemeAttributeChanged();\n break;\n }\n }\n });\n\n this.themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme'],\n });\n }\n\n /**\n * Called when data-theme changes on the document root.\n * Triggers a full re-render when mermaid auto-theming is active.\n */\n private onThemeAttributeChanged(): void {\n if (this.MermaidTheme === 'auto' && this.EnableMermaid && this.hasMermaid && this.Data) {\n this.render();\n }\n }\n\n /**\n * Cleanup event listeners\n */\n private cleanupEventListeners(): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n // Clone and replace to remove all listeners\n const clone = container.cloneNode(true);\n container.parentNode?.replaceChild(clone, container);\n }\n\n /**\n * Force a re-render of the markdown content\n */\n public Refresh(): void {\n this.render();\n }\n\n /** @deprecated Use {@link Refresh}. */\n public refresh(): void {\n return this.Refresh();\n }\n\n /**\n * Get the current heading list (for TOC building)\n */\n public GetHeadings(): HeadingInfo[] {\n return this.markdownService.getHeadingList();\n }\n\n /** @deprecated Use {@link GetHeadings}. */\n public getHeadings(): HeadingInfo[] {\n return this.GetHeadings();\n }\n\n /**\n * Scroll to a heading by ID\n */\n public ScrollToHeading(headingId: string): void {\n const container = this.elementRef.nativeElement.querySelector('.mj-markdown-container');\n if (!container) return;\n\n const heading = container.querySelector(`#${headingId}`);\n if (heading) {\n heading.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }\n\n /** @deprecated Use {@link ScrollToHeading}. */\n public scrollToHeading(headingId: string): void {\n return this.ScrollToHeading(headingId);\n }\n}\n"]}
|
|
@@ -23,6 +23,10 @@ export declare class MarkdownService {
|
|
|
23
23
|
private mermaidEngine;
|
|
24
24
|
/** In-flight load, so N diagrams in one document share ONE chunk fetch. */
|
|
25
25
|
private mermaidLoad;
|
|
26
|
+
/** The KaTeX engine, once its lazy chunk has landed. Null until a formula is actually typeset. */
|
|
27
|
+
private katexEngine;
|
|
28
|
+
/** In-flight load, so N formulas in one document share ONE chunk fetch. */
|
|
29
|
+
private katexLoad;
|
|
26
30
|
/**
|
|
27
31
|
* Prism-backed highlight function injected into the core engine. The engine
|
|
28
32
|
* itself has no Prism dependency — it calls this for the HTML output path.
|
|
@@ -94,6 +98,40 @@ export declare class MarkdownService {
|
|
|
94
98
|
RenderMermaid(container: HTMLElement): Promise<boolean>;
|
|
95
99
|
/** @deprecated Use {@link RenderMermaid}. */
|
|
96
100
|
renderMermaid(container: HTMLElement): Promise<boolean>;
|
|
101
|
+
/**
|
|
102
|
+
* Fetch the KaTeX engine, on first use only. A dynamic `import()` under the "genuine bundle-size
|
|
103
|
+
* deferral" allowance (typescript-style rules, category 3), like {@link loadMermaid}: KaTeX is
|
|
104
|
+
* 277 KB minified (76 KB gzipped), and documents with no math never download it. A failed load
|
|
105
|
+
* clears the cached promise so a later render can retry.
|
|
106
|
+
*/
|
|
107
|
+
private loadKatex;
|
|
108
|
+
/**
|
|
109
|
+
* Spell MathML's styled letters (`mathvariant="bold"`, `"double-struck"`, ...) with their Unicode
|
|
110
|
+
* math characters, which Chrome renders. `RenderMath` already does this; call it on its own when
|
|
111
|
+
* math is off, because MathML that arrived as markup still renders then.
|
|
112
|
+
*
|
|
113
|
+
* @param container The DOM element containing the MathML
|
|
114
|
+
*/
|
|
115
|
+
UseUnicodeMathLetters(container: HTMLElement): void;
|
|
116
|
+
/**
|
|
117
|
+
* Typeset TeX math in a container: every `code.mj-math` placeholder that markdown-core's
|
|
118
|
+
* math extension emitted. Call this after the HTML has been inserted into the DOM. MathML that
|
|
119
|
+
* arrived as markup is already rendered by the browser; it only gets the letter fix below.
|
|
120
|
+
*
|
|
121
|
+
* The output is MathML, which current browsers lay out natively, so hosts need no KaTeX
|
|
122
|
+
* stylesheet or fonts. KaTeX builds the nodes itself from the TeX text (no HTML string is
|
|
123
|
+
* parsed) and runs with `trust` off, so `\href`, `\url` and `\includegraphics` stay inert.
|
|
124
|
+
* A formula KaTeX cannot parse, one that defines macros, or an engine that fails to load leaves
|
|
125
|
+
* the TeX source showing as code. User sizes are capped at 20em.
|
|
126
|
+
*
|
|
127
|
+
* Whether math is on is the caller's decision (`<mj-markdown>` checks its `EnableMath` input):
|
|
128
|
+
* this service is a root singleton whose config the last-rendered component set, so it is no
|
|
129
|
+
* guide to the container in hand. Without math enabled at parse time there are no placeholders.
|
|
130
|
+
*
|
|
131
|
+
* @param container The DOM element containing the math placeholders
|
|
132
|
+
* @returns true if at least one TeX formula was typeset
|
|
133
|
+
*/
|
|
134
|
+
RenderMath(container: HTMLElement): Promise<boolean>;
|
|
97
135
|
/**
|
|
98
136
|
* Mark mermaid blocks as un-renderable, so the failure is VISIBLE rather than a block of
|
|
99
137
|
* raw diagram source the reader can't explain. The `.mermaid-error` class carries the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/markdown.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown.service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/markdown.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
|
|
2
|
+
import katex from 'katex';
|
|
2
3
|
import { MarkdownService } from './markdown.service';
|
|
3
4
|
describe('MarkdownService (DOM)', () => {
|
|
4
5
|
let service;
|
|
@@ -126,6 +127,154 @@ describe('MarkdownService (DOM)', () => {
|
|
|
126
127
|
expect(loads).toBe(0);
|
|
127
128
|
});
|
|
128
129
|
});
|
|
130
|
+
describe('RenderMath', () => {
|
|
131
|
+
/** Parse through the real pipeline (sanitizer included) and mount it, as the component does. */
|
|
132
|
+
const mount = (markdown) => {
|
|
133
|
+
const container = document.createElement('div');
|
|
134
|
+
container.innerHTML = service.Parse(markdown);
|
|
135
|
+
return container;
|
|
136
|
+
};
|
|
137
|
+
const stubLoader = (impl) => {
|
|
138
|
+
service.loadKatex = impl;
|
|
139
|
+
};
|
|
140
|
+
it('typesets inline and display math as MathML with the real engine', async () => {
|
|
141
|
+
const container = mount('Energy $E = mc^2$ where\n\n$$\n\\frac{a}{b}\n$$');
|
|
142
|
+
expect(await service.RenderMath(container)).toBe(true);
|
|
143
|
+
const formulas = container.querySelectorAll('math');
|
|
144
|
+
expect(formulas.length).toBe(2);
|
|
145
|
+
expect(formulas[0].getAttribute('display')).toBeNull();
|
|
146
|
+
expect(formulas[1].getAttribute('display')).toBe('block');
|
|
147
|
+
expect(container.querySelector('mfrac')).not.toBeNull();
|
|
148
|
+
expect(container.querySelector('annotation')?.textContent).toBe('E = mc^2');
|
|
149
|
+
expect(container.querySelector('code.mj-math')).toBeNull();
|
|
150
|
+
});
|
|
151
|
+
it('spells styled letters with Unicode math characters, which Chrome renders (it ignores mathvariant)', async () => {
|
|
152
|
+
const container = mount('$\\mathbf{E} \\in \\mathbb{R}^3, \\mathcal{L}, \\mathfrak{H}, \\mathbf{0}, \\boldsymbol{\\alpha}$');
|
|
153
|
+
await service.RenderMath(container);
|
|
154
|
+
const identifiers = Array.from(container.querySelectorAll('mi, mn')).map((n) => n.textContent);
|
|
155
|
+
expect(identifiers).toEqual(expect.arrayContaining(['𝐄', 'ℝ', 'ℒ', 'ℌ', '𝟎']));
|
|
156
|
+
expect(container.querySelector('mi[mathvariant="bold"], mi[mathvariant="double-struck"]')).toBeNull();
|
|
157
|
+
// Greek has no Unicode form here: it keeps the attribute for the CSS bold fallback.
|
|
158
|
+
expect(container.querySelector('mi[mathvariant="bold-italic"]')?.textContent).toBe('α');
|
|
159
|
+
// The TeX source in the annotation is untouched.
|
|
160
|
+
expect(container.querySelector('annotation')?.textContent).toContain('\\mathbf{E}');
|
|
161
|
+
});
|
|
162
|
+
it('leaves TeX it cannot parse visible as source, and still typesets the rest', async () => {
|
|
163
|
+
const container = mount('Broken $\\frac{a$ but fine $x^2$');
|
|
164
|
+
expect(await service.RenderMath(container)).toBe(true);
|
|
165
|
+
const broken = container.querySelector('code.mj-math.mj-math-error');
|
|
166
|
+
expect(broken?.textContent).toBe('\\frac{a');
|
|
167
|
+
expect(broken?.getAttribute('title')).toBeTruthy();
|
|
168
|
+
expect(container.querySelectorAll('math').length).toBe(1);
|
|
169
|
+
});
|
|
170
|
+
it('leaves a formula that defines macros as source (expansion bombs)', async () => {
|
|
171
|
+
const container = mount('$\\def\\a{x x x}\\a\\a$ and $y$');
|
|
172
|
+
await service.RenderMath(container);
|
|
173
|
+
const kept = container.querySelector('code.mj-math.mj-math-error');
|
|
174
|
+
expect(kept?.textContent).toBe('\\def\\a{x x x}\\a\\a');
|
|
175
|
+
expect(kept?.getAttribute('title')).toContain('macros');
|
|
176
|
+
expect(container.querySelectorAll('math').length).toBe(1);
|
|
177
|
+
});
|
|
178
|
+
it('caps user sizes', async () => {
|
|
179
|
+
const container = mount('$\\rule{100000em}{100000em}$');
|
|
180
|
+
await service.RenderMath(container);
|
|
181
|
+
const rule = container.querySelector('mspace');
|
|
182
|
+
expect(parseFloat(rule?.getAttribute('width') ?? '0')).toBeLessThanOrEqual(20);
|
|
183
|
+
expect(parseFloat(rule?.getAttribute('height') ?? '0')).toBeLessThanOrEqual(20);
|
|
184
|
+
});
|
|
185
|
+
it('skips placeholders a newer render replaced while KaTeX was loading', async () => {
|
|
186
|
+
let release = () => undefined;
|
|
187
|
+
stubLoader(() => new Promise((resolve) => (release = resolve)));
|
|
188
|
+
const container = mount('$x^2$');
|
|
189
|
+
const pending = service.RenderMath(container);
|
|
190
|
+
container.innerHTML = service.Parse('$y^2$'); // the next streamed chunk
|
|
191
|
+
release(katex);
|
|
192
|
+
expect(await pending).toBe(false);
|
|
193
|
+
expect(container.querySelector('math')).toBeNull();
|
|
194
|
+
expect(container.querySelector('code.mj-math')?.textContent).toBe('y^2');
|
|
195
|
+
});
|
|
196
|
+
it('keeps \\href inert (trust is off)', async () => {
|
|
197
|
+
const container = mount('$\\href{javascript:alert(1)}{x}$');
|
|
198
|
+
await service.RenderMath(container);
|
|
199
|
+
// No link anywhere: the command shows as an unrendered "\href". The URL survives only
|
|
200
|
+
// as text inside <annotation>, which is the TeX source and never a link.
|
|
201
|
+
expect(container.querySelector('a, [href]')).toBeNull();
|
|
202
|
+
expect(container.querySelector('mtext')?.textContent).toBe('\\href');
|
|
203
|
+
});
|
|
204
|
+
it('never loads the engine when the document has no math', async () => {
|
|
205
|
+
let loads = 0;
|
|
206
|
+
stubLoader(async () => {
|
|
207
|
+
loads++;
|
|
208
|
+
throw new Error('the engine must not be fetched for a math-free document');
|
|
209
|
+
});
|
|
210
|
+
expect(await service.RenderMath(mount('It costs $5 and $10.'))).toBe(false);
|
|
211
|
+
expect(loads).toBe(0);
|
|
212
|
+
});
|
|
213
|
+
it('leaves the source showing when the lazy chunk cannot be loaded', async () => {
|
|
214
|
+
stubLoader(() => Promise.reject(new Error('chunk fetch failed')));
|
|
215
|
+
const container = mount('$x^2$');
|
|
216
|
+
expect(await service.RenderMath(container)).toBe(false);
|
|
217
|
+
expect(container.querySelector('code.mj-math')?.textContent).toBe('x^2');
|
|
218
|
+
});
|
|
219
|
+
it('does nothing at all when math is disabled by config', async () => {
|
|
220
|
+
let loads = 0;
|
|
221
|
+
stubLoader(async () => {
|
|
222
|
+
loads++;
|
|
223
|
+
throw new Error('the engine must not be fetched when math is disabled');
|
|
224
|
+
});
|
|
225
|
+
service.ConfigureMarked({ enableMath: false });
|
|
226
|
+
const container = mount('$x^2$');
|
|
227
|
+
expect(await service.RenderMath(container)).toBe(false);
|
|
228
|
+
expect(loads).toBe(0);
|
|
229
|
+
expect(container.textContent?.trim()).toBe('$x^2$');
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
describe('MathML markup', () => {
|
|
233
|
+
const MATHML_NS = 'http://www.w3.org/1998/Math/MathML';
|
|
234
|
+
const mount = (markdown) => {
|
|
235
|
+
const container = document.createElement('div');
|
|
236
|
+
container.innerHTML = service.Parse(markdown);
|
|
237
|
+
return container;
|
|
238
|
+
};
|
|
239
|
+
it('keeps a JATS formula as real MathML elements, prefixes removed', () => {
|
|
240
|
+
const c = mount('Loss <mml:math display="inline"><mml:mn>7</mml:mn><mml:mo>×</mml:mo><mml:msup><mml:mn>10</mml:mn><mml:mn>13</mml:mn></mml:msup></mml:math> per pulse.');
|
|
241
|
+
const msup = c.querySelector('msup');
|
|
242
|
+
expect(msup?.namespaceURI).toBe(MATHML_NS);
|
|
243
|
+
expect(msup?.textContent).toBe('1013');
|
|
244
|
+
expect(c.textContent).toContain('per pulse.');
|
|
245
|
+
});
|
|
246
|
+
it('keeps a table\'s column alignment and spacing (DOMPurify misspells one, lacks the other)', () => {
|
|
247
|
+
const c = mount('<math display="block"><mtable columnalign="right left" columnspacing="0em 2em"><mtr><mtd><mi>a</mi></mtd><mtd><mo>=</mo><mi>b</mi></mtd></mtr></mtable></math>');
|
|
248
|
+
const table = c.querySelector('mtable');
|
|
249
|
+
expect(table?.getAttribute('columnalign')).toBe('right left');
|
|
250
|
+
expect(table?.getAttribute('columnspacing')).toBe('0em 2em');
|
|
251
|
+
});
|
|
252
|
+
it('shows the formula once when MathML carries its TeX in an annotation (MathJax, Pandoc, Word)', () => {
|
|
253
|
+
const c = mount('<math><semantics><mrow><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">x^2</annotation></semantics></math>');
|
|
254
|
+
expect(c.querySelector('msup')).not.toBeNull();
|
|
255
|
+
expect(c.textContent?.trim()).toBe('x2');
|
|
256
|
+
});
|
|
257
|
+
it('spells styled letters with Unicode math characters, as for typeset TeX', async () => {
|
|
258
|
+
const c = mount('<math><mi mathvariant="bold">E</mi><mo>∈</mo><msup><mi mathvariant="double-struck">R</mi><mn>3</mn></msup></math>');
|
|
259
|
+
await service.RenderMath(c);
|
|
260
|
+
expect(Array.from(c.querySelectorAll('mi')).map((n) => n.textContent)).toEqual(['𝐄', 'ℝ']);
|
|
261
|
+
});
|
|
262
|
+
// Known DOMPurify bypass shapes through MathML, plus the plain attribute and handler routes.
|
|
263
|
+
it.each([
|
|
264
|
+
['javascript: href on a MathML element', '<math href="javascript:alert(1)"><mi xlink:href="javascript:alert(1)">x</mi></math>'],
|
|
265
|
+
['maction with a script link', '<math><maction actiontype="statusline" xlink:href="javascript:alert(1)"><mi>x</mi></maction></math>'],
|
|
266
|
+
['HTML inside annotation-xml', '<math><annotation-xml encoding="text/html"><img src="x" onerror="alert(1)"></annotation-xml></math>'],
|
|
267
|
+
['mglyph/style namespace confusion', '<math><mtext><table><mglyph><style><img src="x" onerror="alert(1)">'],
|
|
268
|
+
['form/math nesting confusion', '<form><math><mtext></form><form><mglyph><style></math><img src="x" onerror="alert(1)">'],
|
|
269
|
+
['handlers on MathML elements', '<math onclick="alert(1)"><mi onmouseover="alert(1)">x</mi></math>'],
|
|
270
|
+
])('strips %s', (_name, payload) => {
|
|
271
|
+
const c = mount(payload);
|
|
272
|
+
const attributes = Array.from(c.querySelectorAll('*')).flatMap((el) => Array.from(el.attributes));
|
|
273
|
+
expect(attributes.filter((a) => a.name.startsWith('on'))).toEqual([]);
|
|
274
|
+
expect(attributes.filter((a) => /javascript:/i.test(a.value))).toEqual([]);
|
|
275
|
+
expect(c.querySelector('script')).toBeNull();
|
|
276
|
+
});
|
|
277
|
+
});
|
|
129
278
|
describe('parse sanitizes unless scripts are explicitly enabled', () => {
|
|
130
279
|
it('strips handlers and script from passthrough HTML', () => {
|
|
131
280
|
const out = service.parse('<div><img src="x" onerror="alert(1)"><script>alert(2)</script></div>', { enableHtml: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.service.dom.test.js","sourceRoot":"","sources":["../../../src/lib/services/markdown.service.dom.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEzE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAmBrD,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,OAAwB,CAAC;IAC7B,IAAI,MAAgC,CAAC;IAErC,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;QAChC,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAE,OAAqC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAC7E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,EAAE,GAAG,UAAU,CAAC;YACtB,MAAM,CAAC,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,IAAI,GAAG,yBAAyB,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;YAC/E,MAAM,IAAI,GAAG,8DAA8D,CAAC;YAC5E,uDAAuD;YACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;YAC3E,MAAM,IAAI,GAAG,iGAAiG,CAAC;YAC/G,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,mEAAmE;YACnE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YACvC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;YAC/E,gFAAgF;YAChF,MAAM,IAAI,GAAG,2EAA2E,CAAC;YACzF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC/B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YACxC,4CAA4C;YAC5C,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACzC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;YAC9E,MAAM,IAAI,GAAG,oCAAoC,CAAC;YAClD,qEAAqE;YACrE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,IAAI,GAAG,0BAA0B,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,IAAI,GAAG,kDAAkD,CAAC;YAChE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACnF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,OAAO,CAAC,eAAe,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,oEAAoE;YACpE,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7D,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,2BAA2B,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,yGAAyG;QACzG,MAAM,UAAU,GAAG,CAAC,IAA4B,EAAQ,EAAE;YACvD,OAA4C,CAAC,WAAW,GAAG,IAAI,CAAC;QACnE,CAAC,CAAC;QAEF,MAAM,aAAa,GAAG,CAAC,IAAY,EAAe,EAAE;YAClD,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAChD,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC;YAC3B,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC;QAEF,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;YAC/E,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,UAAU,CAAC,KAAK,IAAI,EAAE;gBACpB,KAAK,EAAE,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;YAChF,CAAC,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC,CAAC;YAErF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;YAC3F,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;YAClE,MAAM,SAAS,GAAG,aAAa,CAC7B,mEAAmE;gBACnE,6CAA6C,CAC9C,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;YAEtD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;YAC5D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;YACtE,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,UAAU,CAAC,KAAK,IAAI,EAAE;gBACpB,KAAK,EAAE,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAC7E,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,eAAe,CAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;YAElD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,aAAa,CACxC,aAAa,CAAC,mEAAmE,CAAC,CACnF,CAAC;YAEF,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uDAAuD,EAAE,GAAG,EAAE;QACrE,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,sEAAsE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YACxH,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;YAC5E,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;YACjH,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;YACnF,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,mDAAmD,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrG,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qDAAqD,EAAE,GAAG,EAAE;QACnE,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,oKAAoK,CAAC;QAEtL,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;YACtE,kFAAkF;YAClF,4DAA4D;YAC5D,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;YAC1D,MAAM,CAAC,QAAQ,CAAC,CAAC;YACjB,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;YACzD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';\nimport type { Mermaid } from 'mermaid';\nimport { MarkdownService } from './markdown.service';\n\n/**\n * jsdom specs for the web shell around @memberjunction/markdown-core.\n *\n * These focus on the browser-only concerns that stay in the Angular service:\n * the `parse()` entry points and the DOM-based `unwrapMiscodedHtml()` fixup.\n * The framework-agnostic parsing itself is covered in @memberjunction/markdown-core.\n *\n * `unwrapMiscodedHtml` is private, so we reach it through a typed cast — the same\n * pattern the markdown-core engine spec uses to poke the internal marked instance.\n * This keeps the assertions deterministic (exact HTML in, exact behavior out)\n * rather than depending on which fixtures marked happens to miscode.\n */\ntype UnwrapAccessor = { unwrapMiscodedHtml(html: string): string };\n\n/** Same private-member reach-in, for the lazily-loaded mermaid engine (see `loadMermaid`). */\ntype MermaidLoaderAccessor = { loadMermaid(): Promise<Mermaid> };\n\ndescribe('MarkdownService (DOM)', () => {\n let service: MarkdownService;\n let unwrap: (html: string) => string;\n\n beforeEach(() => {\n service = new MarkdownService();\n unwrap = (html: string) => (service as unknown as UnwrapAccessor).unwrapMiscodedHtml(html);\n });\n\n describe('parse', () => {\n it('returns empty string for empty input', () => {\n expect(service.parse('')).toBe('');\n });\n\n it('renders basic prose to a paragraph', () => {\n expect(service.parse('hello world')).toContain('<p>');\n });\n\n it('accepts per-call config overrides without throwing', () => {\n expect(() => service.parse('# Title', { enableHtml: true })).not.toThrow();\n });\n\n it('parseAsync resolves to the same output as parse', async () => {\n const md = '**bold**';\n expect(await service.parseAsync(md)).toBe(service.parse(md));\n });\n });\n\n describe('unwrapMiscodedHtml', () => {\n it('is a no-op when there are no <pre> blocks', () => {\n const html = '<p>just a paragraph</p>';\n expect(unwrap(html)).toBe(html);\n });\n\n it('returns empty input unchanged', () => {\n expect(unwrap('')).toBe('');\n });\n\n it('skips content containing <svg (DOMParser would mangle SVG namespaces)', () => {\n const html = '<pre><code><svg><rect/></svg></code></pre>';\n // Left untouched precisely because it contains \"<svg\".\n expect(unwrap(html)).toBe(html);\n });\n\n it('preserves an intentional code block that carries a language class', () => {\n const html = '<pre><code class=\"language-html\"><div><span>x</span></div></code></pre>';\n const out = unwrap(html);\n // Language-classed code is an intentional example → NOT unwrapped.\n expect(out).toContain('language-html');\n expect(out).toContain('<pre>');\n });\n\n it('unwraps structural HTML that marked miscoded into a <pre><code> block', () => {\n // textContent decodes to <div><span>x</span></div> — multi-tag structural HTML.\n const html = '<pre><code><div><span>x</span></div></code></pre>';\n const out = unwrap(html);\n expect(out).toContain('<div>');\n expect(out).toContain('<span>x</span>');\n // The escaped code-block form must be gone.\n expect(out).not.toContain('<div>');\n expect(out).not.toContain('<pre>');\n });\n\n it('does not unwrap a single self-closing tag (needs 2+ tags to qualify)', () => {\n const html = '<pre><code><br></code></pre>';\n // tagCount < 2 → looksLikeStructuralHtml returns false → left as-is.\n expect(unwrap(html)).toBe(html);\n });\n\n it('does not unwrap an empty code block', () => {\n const html = '<pre><code></code></pre>';\n expect(unwrap(html)).toBe(html);\n });\n\n it('does not unwrap plain non-HTML code content', () => {\n const html = '<pre><code>const x = 1; // not html</code></pre>';\n expect(unwrap(html)).toBe(html);\n });\n\n it('does not throw on malformed markup', () => {\n expect(() => unwrap('<pre><code><div><span>unclosed')).not.toThrow();\n });\n });\n\n describe('config accessors', () => {\n it('resetConfig restores enableHtml to the default (false)', () => {\n service.configureMarked({ enableHtml: true });\n expect(service.getConfig().enableHtml).toBe(true);\n service.resetConfig();\n expect(service.getConfig().enableHtml).toBe(false);\n });\n\n it('isLanguageSupported reflects Prism registration', () => {\n // typescript is imported by the service; a made-up language is not.\n expect(service.isLanguageSupported('typescript')).toBe(true);\n expect(service.isLanguageSupported('definitely-not-a-language')).toBe(false);\n });\n });\n\n describe('renderMermaid', () => {\n /** Stub the private lazy loader — the point of these specs is WHEN it is called, not what it returns. */\n const stubLoader = (impl: () => Promise<Mermaid>): void => {\n (service as unknown as MermaidLoaderAccessor).loadMermaid = impl;\n };\n\n const containerWith = (html: string): HTMLElement => {\n const container = document.createElement('div');\n container.innerHTML = html;\n return container;\n };\n\n it('never loads the diagram engine when the document has no diagram', async () => {\n let loads = 0;\n stubLoader(async () => {\n loads++;\n throw new Error('the engine must not be fetched for a diagram-free document');\n });\n\n const result = await service.renderMermaid(containerWith('<p>no diagrams here</p>'));\n\n expect(result).toBe(false);\n expect(loads).toBe(0);\n });\n\n it('shows a visible failure on every block when the lazy chunk cannot be loaded', async () => {\n stubLoader(() => Promise.reject(new Error('chunk fetch failed')));\n const container = containerWith(\n '<pre><code class=\"language-mermaid\">graph TD; A-->B;</code></pre>' +\n '<div class=\"mermaid\">graph TD; C-->D;</div>',\n );\n\n const result = await service.renderMermaid(container);\n\n expect(result).toBe(false);\n const failed = container.querySelectorAll('.mermaid-error');\n expect(failed.length).toBe(2);\n for (const element of Array.from(failed)) {\n expect(element.getAttribute('data-mermaid-error')).toBe('Diagram engine failed to load');\n }\n });\n\n it('does nothing at all when mermaid is disabled by config', async () => {\n let loads = 0;\n stubLoader(async () => {\n loads++;\n throw new Error('the engine must not be fetched when mermaid is disabled');\n });\n service.configureMarked({ enableMermaid: false });\n\n const result = await service.renderMermaid(\n containerWith('<pre><code class=\"language-mermaid\">graph TD; A-->B;</code></pre>'),\n );\n\n expect(result).toBe(false);\n expect(loads).toBe(0);\n });\n });\n\n describe('parse sanitizes unless scripts are explicitly enabled', () => {\n it('strips handlers and script from passthrough HTML', () => {\n const out = service.parse('<div><img src=\"x\" onerror=\"alert(1)\"><script>alert(2)</script></div>', { enableHtml: true });\n expect(out).not.toContain('onerror');\n expect(out).not.toContain('<script');\n expect(out).toContain('<img');\n });\n\n it('leaves script in place when enableJavaScript is true (the opt-out)', () => {\n const out = service.parse('<div>x</div><script>alert(1)</script>', { enableHtml: true, enableJavaScript: true });\n expect(out).toContain('<script>');\n });\n\n it('sanitizeHtml is exposed for consumers that bind parse() output themselves', () => {\n expect(service.sanitizeHtml('<a href=\"javascript:alert(1)\" onclick=\"x()\">x</a>')).toBe('<a>x</a>');\n });\n });\n\n describe('unwrapMiscodedHtml is inert and keeps leading style', () => {\n afterEach(() => vi.restoreAllMocks());\n const miscoded = '<pre><code><style>.card{color:red}</style><div class=\"card\"><img src=\"x\" onerror=\"alert(1)\"><p>hi</p></div></code></pre>';\n\n it('never creates elements on the live document while unwrapping', () => {\n // Building the replacement on the live document would run image error handlers at\n // parse time, before parse() sanitizes the returned string.\n const createElement = vi.spyOn(document, 'createElement');\n unwrap(miscoded);\n expect(createElement).not.toHaveBeenCalled();\n });\n\n it('unwraps the structural HTML and keeps a leading <style>', () => {\n const out = unwrap(miscoded);\n expect(out).not.toContain('<pre>');\n expect(out).toContain('<style>.card{color:red}</style>');\n expect(out).toContain('<div class=\"card\">');\n });\n\n it('returns markup for parse() to sanitize rather than executing it', () => {\n expect(unwrap(miscoded)).toContain('onerror=\"alert(1)\"');\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"markdown.service.dom.test.js","sourceRoot":"","sources":["../../../src/lib/services/markdown.service.dom.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';\nimport type { Mermaid } from 'mermaid';\nimport katex from 'katex';\nimport { MarkdownService } from './markdown.service';\n\n/**\n * jsdom specs for the web shell around @memberjunction/markdown-core.\n *\n * These focus on the browser-only concerns that stay in the Angular service:\n * the `parse()` entry points and the DOM-based `unwrapMiscodedHtml()` fixup.\n * The framework-agnostic parsing itself is covered in @memberjunction/markdown-core.\n *\n * `unwrapMiscodedHtml` is private, so we reach it through a typed cast — the same\n * pattern the markdown-core engine spec uses to poke the internal marked instance.\n * This keeps the assertions deterministic (exact HTML in, exact behavior out)\n * rather than depending on which fixtures marked happens to miscode.\n */\ntype UnwrapAccessor = { unwrapMiscodedHtml(html: string): string };\n\n/** Same private-member reach-in, for the lazily-loaded mermaid engine (see `loadMermaid`). */\ntype MermaidLoaderAccessor = { loadMermaid(): Promise<Mermaid> };\n\n/** And for the lazily-loaded KaTeX engine (see `loadKatex`). */\ntype KatexLoaderAccessor = { loadKatex(): Promise<unknown> };\n\ndescribe('MarkdownService (DOM)', () => {\n let service: MarkdownService;\n let unwrap: (html: string) => string;\n\n beforeEach(() => {\n service = new MarkdownService();\n unwrap = (html: string) => (service as unknown as UnwrapAccessor).unwrapMiscodedHtml(html);\n });\n\n describe('parse', () => {\n it('returns empty string for empty input', () => {\n expect(service.parse('')).toBe('');\n });\n\n it('renders basic prose to a paragraph', () => {\n expect(service.parse('hello world')).toContain('<p>');\n });\n\n it('accepts per-call config overrides without throwing', () => {\n expect(() => service.parse('# Title', { enableHtml: true })).not.toThrow();\n });\n\n it('parseAsync resolves to the same output as parse', async () => {\n const md = '**bold**';\n expect(await service.parseAsync(md)).toBe(service.parse(md));\n });\n });\n\n describe('unwrapMiscodedHtml', () => {\n it('is a no-op when there are no <pre> blocks', () => {\n const html = '<p>just a paragraph</p>';\n expect(unwrap(html)).toBe(html);\n });\n\n it('returns empty input unchanged', () => {\n expect(unwrap('')).toBe('');\n });\n\n it('skips content containing <svg (DOMParser would mangle SVG namespaces)', () => {\n const html = '<pre><code><svg><rect/></svg></code></pre>';\n // Left untouched precisely because it contains \"<svg\".\n expect(unwrap(html)).toBe(html);\n });\n\n it('preserves an intentional code block that carries a language class', () => {\n const html = '<pre><code class=\"language-html\"><div><span>x</span></div></code></pre>';\n const out = unwrap(html);\n // Language-classed code is an intentional example → NOT unwrapped.\n expect(out).toContain('language-html');\n expect(out).toContain('<pre>');\n });\n\n it('unwraps structural HTML that marked miscoded into a <pre><code> block', () => {\n // textContent decodes to <div><span>x</span></div> — multi-tag structural HTML.\n const html = '<pre><code><div><span>x</span></div></code></pre>';\n const out = unwrap(html);\n expect(out).toContain('<div>');\n expect(out).toContain('<span>x</span>');\n // The escaped code-block form must be gone.\n expect(out).not.toContain('<div>');\n expect(out).not.toContain('<pre>');\n });\n\n it('does not unwrap a single self-closing tag (needs 2+ tags to qualify)', () => {\n const html = '<pre><code><br></code></pre>';\n // tagCount < 2 → looksLikeStructuralHtml returns false → left as-is.\n expect(unwrap(html)).toBe(html);\n });\n\n it('does not unwrap an empty code block', () => {\n const html = '<pre><code></code></pre>';\n expect(unwrap(html)).toBe(html);\n });\n\n it('does not unwrap plain non-HTML code content', () => {\n const html = '<pre><code>const x = 1; // not html</code></pre>';\n expect(unwrap(html)).toBe(html);\n });\n\n it('does not throw on malformed markup', () => {\n expect(() => unwrap('<pre><code><div><span>unclosed')).not.toThrow();\n });\n });\n\n describe('config accessors', () => {\n it('resetConfig restores enableHtml to the default (false)', () => {\n service.configureMarked({ enableHtml: true });\n expect(service.getConfig().enableHtml).toBe(true);\n service.resetConfig();\n expect(service.getConfig().enableHtml).toBe(false);\n });\n\n it('isLanguageSupported reflects Prism registration', () => {\n // typescript is imported by the service; a made-up language is not.\n expect(service.isLanguageSupported('typescript')).toBe(true);\n expect(service.isLanguageSupported('definitely-not-a-language')).toBe(false);\n });\n });\n\n describe('renderMermaid', () => {\n /** Stub the private lazy loader — the point of these specs is WHEN it is called, not what it returns. */\n const stubLoader = (impl: () => Promise<Mermaid>): void => {\n (service as unknown as MermaidLoaderAccessor).loadMermaid = impl;\n };\n\n const containerWith = (html: string): HTMLElement => {\n const container = document.createElement('div');\n container.innerHTML = html;\n return container;\n };\n\n it('never loads the diagram engine when the document has no diagram', async () => {\n let loads = 0;\n stubLoader(async () => {\n loads++;\n throw new Error('the engine must not be fetched for a diagram-free document');\n });\n\n const result = await service.renderMermaid(containerWith('<p>no diagrams here</p>'));\n\n expect(result).toBe(false);\n expect(loads).toBe(0);\n });\n\n it('shows a visible failure on every block when the lazy chunk cannot be loaded', async () => {\n stubLoader(() => Promise.reject(new Error('chunk fetch failed')));\n const container = containerWith(\n '<pre><code class=\"language-mermaid\">graph TD; A-->B;</code></pre>' +\n '<div class=\"mermaid\">graph TD; C-->D;</div>',\n );\n\n const result = await service.renderMermaid(container);\n\n expect(result).toBe(false);\n const failed = container.querySelectorAll('.mermaid-error');\n expect(failed.length).toBe(2);\n for (const element of Array.from(failed)) {\n expect(element.getAttribute('data-mermaid-error')).toBe('Diagram engine failed to load');\n }\n });\n\n it('does nothing at all when mermaid is disabled by config', async () => {\n let loads = 0;\n stubLoader(async () => {\n loads++;\n throw new Error('the engine must not be fetched when mermaid is disabled');\n });\n service.configureMarked({ enableMermaid: false });\n\n const result = await service.renderMermaid(\n containerWith('<pre><code class=\"language-mermaid\">graph TD; A-->B;</code></pre>'),\n );\n\n expect(result).toBe(false);\n expect(loads).toBe(0);\n });\n });\n\n describe('RenderMath', () => {\n /** Parse through the real pipeline (sanitizer included) and mount it, as the component does. */\n const mount = (markdown: string): HTMLElement => {\n const container = document.createElement('div');\n container.innerHTML = service.Parse(markdown);\n return container;\n };\n\n const stubLoader = (impl: () => Promise<unknown>): void => {\n (service as unknown as KatexLoaderAccessor).loadKatex = impl;\n };\n\n it('typesets inline and display math as MathML with the real engine', async () => {\n const container = mount('Energy $E = mc^2$ where\\n\\n$$\\n\\\\frac{a}{b}\\n$$');\n\n expect(await service.RenderMath(container)).toBe(true);\n\n const formulas = container.querySelectorAll('math');\n expect(formulas.length).toBe(2);\n expect(formulas[0].getAttribute('display')).toBeNull();\n expect(formulas[1].getAttribute('display')).toBe('block');\n expect(container.querySelector('mfrac')).not.toBeNull();\n expect(container.querySelector('annotation')?.textContent).toBe('E = mc^2');\n expect(container.querySelector('code.mj-math')).toBeNull();\n });\n\n it('spells styled letters with Unicode math characters, which Chrome renders (it ignores mathvariant)', async () => {\n const container = mount('$\\\\mathbf{E} \\\\in \\\\mathbb{R}^3, \\\\mathcal{L}, \\\\mathfrak{H}, \\\\mathbf{0}, \\\\boldsymbol{\\\\alpha}$');\n\n await service.RenderMath(container);\n\n const identifiers = Array.from(container.querySelectorAll('mi, mn')).map((n) => n.textContent);\n expect(identifiers).toEqual(expect.arrayContaining(['𝐄', 'ℝ', 'ℒ', 'ℌ', '𝟎']));\n expect(container.querySelector('mi[mathvariant=\"bold\"], mi[mathvariant=\"double-struck\"]')).toBeNull();\n // Greek has no Unicode form here: it keeps the attribute for the CSS bold fallback.\n expect(container.querySelector('mi[mathvariant=\"bold-italic\"]')?.textContent).toBe('α');\n // The TeX source in the annotation is untouched.\n expect(container.querySelector('annotation')?.textContent).toContain('\\\\mathbf{E}');\n });\n\n it('leaves TeX it cannot parse visible as source, and still typesets the rest', async () => {\n const container = mount('Broken $\\\\frac{a$ but fine $x^2$');\n\n expect(await service.RenderMath(container)).toBe(true);\n\n const broken = container.querySelector('code.mj-math.mj-math-error');\n expect(broken?.textContent).toBe('\\\\frac{a');\n expect(broken?.getAttribute('title')).toBeTruthy();\n expect(container.querySelectorAll('math').length).toBe(1);\n });\n\n it('leaves a formula that defines macros as source (expansion bombs)', async () => {\n const container = mount('$\\\\def\\\\a{x x x}\\\\a\\\\a$ and $y$');\n\n await service.RenderMath(container);\n\n const kept = container.querySelector('code.mj-math.mj-math-error');\n expect(kept?.textContent).toBe('\\\\def\\\\a{x x x}\\\\a\\\\a');\n expect(kept?.getAttribute('title')).toContain('macros');\n expect(container.querySelectorAll('math').length).toBe(1);\n });\n\n it('caps user sizes', async () => {\n const container = mount('$\\\\rule{100000em}{100000em}$');\n\n await service.RenderMath(container);\n\n const rule = container.querySelector('mspace');\n expect(parseFloat(rule?.getAttribute('width') ?? '0')).toBeLessThanOrEqual(20);\n expect(parseFloat(rule?.getAttribute('height') ?? '0')).toBeLessThanOrEqual(20);\n });\n\n it('skips placeholders a newer render replaced while KaTeX was loading', async () => {\n let release: (engine: unknown) => void = () => undefined;\n stubLoader(() => new Promise((resolve) => (release = resolve)));\n const container = mount('$x^2$');\n\n const pending = service.RenderMath(container);\n container.innerHTML = service.Parse('$y^2$'); // the next streamed chunk\n release(katex);\n\n expect(await pending).toBe(false);\n expect(container.querySelector('math')).toBeNull();\n expect(container.querySelector('code.mj-math')?.textContent).toBe('y^2');\n });\n\n it('keeps \\\\href inert (trust is off)', async () => {\n const container = mount('$\\\\href{javascript:alert(1)}{x}$');\n\n await service.RenderMath(container);\n\n // No link anywhere: the command shows as an unrendered \"\\href\". The URL survives only\n // as text inside <annotation>, which is the TeX source and never a link.\n expect(container.querySelector('a, [href]')).toBeNull();\n expect(container.querySelector('mtext')?.textContent).toBe('\\\\href');\n });\n\n it('never loads the engine when the document has no math', async () => {\n let loads = 0;\n stubLoader(async () => {\n loads++;\n throw new Error('the engine must not be fetched for a math-free document');\n });\n\n expect(await service.RenderMath(mount('It costs $5 and $10.'))).toBe(false);\n expect(loads).toBe(0);\n });\n\n it('leaves the source showing when the lazy chunk cannot be loaded', async () => {\n stubLoader(() => Promise.reject(new Error('chunk fetch failed')));\n const container = mount('$x^2$');\n\n expect(await service.RenderMath(container)).toBe(false);\n expect(container.querySelector('code.mj-math')?.textContent).toBe('x^2');\n });\n\n it('does nothing at all when math is disabled by config', async () => {\n let loads = 0;\n stubLoader(async () => {\n loads++;\n throw new Error('the engine must not be fetched when math is disabled');\n });\n service.ConfigureMarked({ enableMath: false });\n\n const container = mount('$x^2$');\n\n expect(await service.RenderMath(container)).toBe(false);\n expect(loads).toBe(0);\n expect(container.textContent?.trim()).toBe('$x^2$');\n });\n });\n\n describe('MathML markup', () => {\n const MATHML_NS = 'http://www.w3.org/1998/Math/MathML';\n const mount = (markdown: string): HTMLElement => {\n const container = document.createElement('div');\n container.innerHTML = service.Parse(markdown);\n return container;\n };\n\n it('keeps a JATS formula as real MathML elements, prefixes removed', () => {\n const c = mount('Loss <mml:math display=\"inline\"><mml:mn>7</mml:mn><mml:mo>×</mml:mo><mml:msup><mml:mn>10</mml:mn><mml:mn>13</mml:mn></mml:msup></mml:math> per pulse.');\n const msup = c.querySelector('msup');\n expect(msup?.namespaceURI).toBe(MATHML_NS);\n expect(msup?.textContent).toBe('1013');\n expect(c.textContent).toContain('per pulse.');\n });\n\n it('keeps a table\\'s column alignment and spacing (DOMPurify misspells one, lacks the other)', () => {\n const c = mount('<math display=\"block\"><mtable columnalign=\"right left\" columnspacing=\"0em 2em\"><mtr><mtd><mi>a</mi></mtd><mtd><mo>=</mo><mi>b</mi></mtd></mtr></mtable></math>');\n const table = c.querySelector('mtable');\n expect(table?.getAttribute('columnalign')).toBe('right left');\n expect(table?.getAttribute('columnspacing')).toBe('0em 2em');\n });\n\n it('shows the formula once when MathML carries its TeX in an annotation (MathJax, Pandoc, Word)', () => {\n const c = mount('<math><semantics><mrow><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding=\"application/x-tex\">x^2</annotation></semantics></math>');\n expect(c.querySelector('msup')).not.toBeNull();\n expect(c.textContent?.trim()).toBe('x2');\n });\n\n it('spells styled letters with Unicode math characters, as for typeset TeX', async () => {\n const c = mount('<math><mi mathvariant=\"bold\">E</mi><mo>∈</mo><msup><mi mathvariant=\"double-struck\">R</mi><mn>3</mn></msup></math>');\n await service.RenderMath(c);\n expect(Array.from(c.querySelectorAll('mi')).map((n) => n.textContent)).toEqual(['𝐄', 'ℝ']);\n });\n\n // Known DOMPurify bypass shapes through MathML, plus the plain attribute and handler routes.\n it.each([\n ['javascript: href on a MathML element', '<math href=\"javascript:alert(1)\"><mi xlink:href=\"javascript:alert(1)\">x</mi></math>'],\n ['maction with a script link', '<math><maction actiontype=\"statusline\" xlink:href=\"javascript:alert(1)\"><mi>x</mi></maction></math>'],\n ['HTML inside annotation-xml', '<math><annotation-xml encoding=\"text/html\"><img src=\"x\" onerror=\"alert(1)\"></annotation-xml></math>'],\n ['mglyph/style namespace confusion', '<math><mtext><table><mglyph><style><img src=\"x\" onerror=\"alert(1)\">'],\n ['form/math nesting confusion', '<form><math><mtext></form><form><mglyph><style></math><img src=\"x\" onerror=\"alert(1)\">'],\n ['handlers on MathML elements', '<math onclick=\"alert(1)\"><mi onmouseover=\"alert(1)\">x</mi></math>'],\n ])('strips %s', (_name, payload) => {\n const c = mount(payload);\n const attributes = Array.from(c.querySelectorAll('*')).flatMap((el) => Array.from(el.attributes));\n expect(attributes.filter((a) => a.name.startsWith('on'))).toEqual([]);\n expect(attributes.filter((a) => /javascript:/i.test(a.value))).toEqual([]);\n expect(c.querySelector('script')).toBeNull();\n });\n });\n\n describe('parse sanitizes unless scripts are explicitly enabled', () => {\n it('strips handlers and script from passthrough HTML', () => {\n const out = service.parse('<div><img src=\"x\" onerror=\"alert(1)\"><script>alert(2)</script></div>', { enableHtml: true });\n expect(out).not.toContain('onerror');\n expect(out).not.toContain('<script');\n expect(out).toContain('<img');\n });\n\n it('leaves script in place when enableJavaScript is true (the opt-out)', () => {\n const out = service.parse('<div>x</div><script>alert(1)</script>', { enableHtml: true, enableJavaScript: true });\n expect(out).toContain('<script>');\n });\n\n it('sanitizeHtml is exposed for consumers that bind parse() output themselves', () => {\n expect(service.sanitizeHtml('<a href=\"javascript:alert(1)\" onclick=\"x()\">x</a>')).toBe('<a>x</a>');\n });\n });\n\n describe('unwrapMiscodedHtml is inert and keeps leading style', () => {\n afterEach(() => vi.restoreAllMocks());\n const miscoded = '<pre><code><style>.card{color:red}</style><div class=\"card\"><img src=\"x\" onerror=\"alert(1)\"><p>hi</p></div></code></pre>';\n\n it('never creates elements on the live document while unwrapping', () => {\n // Building the replacement on the live document would run image error handlers at\n // parse time, before parse() sanitizes the returned string.\n const createElement = vi.spyOn(document, 'createElement');\n unwrap(miscoded);\n expect(createElement).not.toHaveBeenCalled();\n });\n\n it('unwraps the structural HTML and keeps a leading <style>', () => {\n const out = unwrap(miscoded);\n expect(out).not.toContain('<pre>');\n expect(out).toContain('<style>.card{color:red}</style>');\n expect(out).toContain('<div class=\"card\">');\n });\n\n it('returns markup for parse() to sanitize rather than executing it', () => {\n expect(unwrap(miscoded)).toContain('onerror=\"alert(1)\"');\n });\n });\n});\n"]}
|