@@ -47,7 +47,7 @@ class ParsedownToC extends DynamicParent
4747 * Constants.
4848 * ------------------------------------------------------------------------
4949 */
50- const version = '1.1.1 ' ; // Version is available since v1.1.0
50+ const version = '1.1.2 ' ; // Version is available since v1.1.0
5151 const VERSION_PARSEDOWN_REQUIRED = '1.7 ' ;
5252 const TAG_TOC_DEFAULT = '[toc] ' ;
5353 const ID_ATTRIBUTE_DEFAULT = 'toc ' ;
@@ -124,15 +124,19 @@ protected function blockHeader($Line)
124124 }
125125
126126 /**
127- * Parses the given markdown string to an HTML string.
128- * It's an alias of the parent method: \Parsedown ::text()
127+ * Parses the given markdown string to an HTML string but it leaves the ToC
128+ * tag as is. It's an alias of the parent method "\DynamicParent ::text()".
129129 *
130130 * @param string $text Markdown string to be parsed.
131131 * @return string Parsed HTML string.
132132 */
133133 public function body ($ text )
134134 {
135- return DynamicParent::text ($ text );
135+ $ text = $ this ->encodeTagToHash ($ text ); // Escapes ToC tag temporary
136+ $ html = DynamicParent::text ($ text ); // Parses the markdown text
137+ $ html = $ this ->decodeTagFromHash ($ html ); // Unescape the ToC tag
138+
139+ return $ html ;
136140 }
137141
138142 /**
@@ -167,7 +171,8 @@ public function contentsList($type_return = 'string')
167171 }
168172
169173 /**
170- * Generates link-able anchor from the text.
174+ * Generates an anchor text that are link-able even the heading is not in
175+ * ASCII.
171176 *
172177 * @param string $text
173178 * @return string
@@ -177,6 +182,53 @@ protected function createAnchorID($text)
177182 return urlencode ($ this ->fetchText ($ text ));
178183 }
179184
185+ /**
186+ * Decodes the hashed ToC tag to an original tag and replaces.
187+ *
188+ * This is used to avoid parsing user defined ToC tag which includes "_" in
189+ * their tag such as "[[_toc_]]". Unless it will be parsed as:
190+ * "<p>[[<em>TOC</em>]]</p>"
191+ *
192+ * @param string $text
193+ * @return string
194+ */
195+ protected function decodeTagFromHash ($ text )
196+ {
197+ $ salt = $ this ->getSalt ();
198+ $ tag_origin = $ this ->getTagToC ();
199+ $ tag_hashed = hash ('sha256 ' , $ salt . $ tag_origin );
200+
201+ if (strpos ($ text , $ tag_hashed ) === false ) {
202+ return $ text ;
203+ }
204+
205+ return str_replace ($ tag_hashed , $ tag_origin , $ text );
206+ }
207+
208+ /**
209+ * Encodes the ToC tag to a hashed tag and replace.
210+ *
211+ * This is used to avoid parsing user defined ToC tag which includes "_" in
212+ * their tag such as "[[_toc_]]". Unless it will be parsed as:
213+ * "<p>[[<em>TOC</em>]]</p>"
214+ *
215+ * @param string $text
216+ * @return string
217+ */
218+ protected function encodeTagToHash ($ text )
219+ {
220+ $ salt = $ this ->getSalt ();
221+ $ tag_origin = $ this ->getTagToC ();
222+
223+ if (strpos ($ text , $ tag_origin ) === false ) {
224+ return $ text ;
225+ }
226+
227+ $ tag_hashed = hash ('sha256 ' , $ salt . $ tag_origin );
228+
229+ return str_replace ($ tag_origin , $ tag_hashed , $ text );
230+ }
231+
180232 /**
181233 * Get only the text from a markdown string.
182234 * It parses to HTML once then trims the tags to get the text.
@@ -204,35 +256,33 @@ protected function getIdAttributeToC()
204256 }
205257
206258 /**
207- * Gets the markdown tag for ToC .
259+ * Unique string to use as a salt value .
208260 *
209261 * @return string
210262 */
211- protected function getTagToC ()
263+ protected function getSalt ()
212264 {
213- if (isset ($ this ->tag_toc ) && ! empty ($ this ->tag_toc )) {
214- return $ this ->tag_toc ;
265+ static $ salt ;
266+ if (isset ($ salt )) {
267+ return $ salt ;
215268 }
216269
217- return self ::TAG_TOC_DEFAULT ;
270+ $ salt = hash ('md5 ' , time ());
271+ return $ salt ;
218272 }
219273
220274 /**
221- * Replaces the "[toc]" tag (by default) to the parsed ToC list .
275+ * Gets the markdown tag for ToC.
222276 *
223- * @param string $html Parsed HTML string
224- * @return string Parsed HTML string with parsed ToC.
277+ * @return string
225278 */
226- protected function replaceTagToC ( $ html )
279+ protected function getTagToC ( )
227280 {
228- $ toc = $ this ->contentsList ();
229- $ tag_toc = $ this ->getTagToC ();
230- $ id_toc = $ this ->getIdAttributeToC ();
231-
232- $ needle = '<p> ' . $ tag_toc . '</p> ' ;
233- $ replace = "<div id= \"$ {id_toc}\"> $ {toc}</div> " ;
281+ if (isset ($ this ->tag_toc ) && ! empty ($ this ->tag_toc )) {
282+ return $ this ->tag_toc ;
283+ }
234284
235- return str_replace ( $ needle , $ replace , $ html ) ;
285+ return self :: TAG_TOC_DEFAULT ;
236286 }
237287
238288 /**
@@ -297,6 +347,29 @@ protected function setContentsListAsString(array $Content)
297347 protected $ contentsListString = '' ;
298348 protected $ firstHeadLevel = 0 ;
299349
350+ /**
351+ * Sets the user defined ToC markdown tag.
352+ *
353+ * @param string $tag
354+ * @return void
355+ */
356+ public function setTagToc ($ tag )
357+ {
358+ $ tag = trim ($ tag );
359+ if (self ::escape ($ tag ) === $ tag ) {
360+ // Set ToC tag if it's safe
361+ $ this ->tag_toc = $ tag ;
362+ } else {
363+ // Do nothing but log
364+ error_log (
365+ 'Malformed ToC user tag given. '
366+ . ' At: ' . __FUNCTION__ . '() '
367+ . ' in Line: ' . __LINE__ . ' (Using default ToC tag) '
368+ );
369+ }
370+ }
371+ protected $ tag_toc ='' ;
372+
300373 /**
301374 * Parses markdown string to HTML and also the "[toc]" tag as well.
302375 * It overrides the parent method: \Parsedown::text().
@@ -306,13 +379,22 @@ protected function setContentsListAsString(array $Content)
306379 */
307380 public function text ($ text )
308381 {
309- $ body = $ this ->body ($ text );
310- $ tag = $ this ->getTagToC ();
382+ // Parses the markdown text except the ToC tag. This also searches
383+ // the list of contents and available to get from "contentsList()"
384+ // method.
385+ $ html = $ this ->body ($ text );
311386
312- if (strpos ($ text , $ tag ) === false ) {
313- return $ body ;
387+ $ tag_origin = $ this ->getTagToC ();
388+
389+ if (strpos ($ text , $ tag_origin ) === false ) {
390+ return $ html ;
314391 }
315392
316- return $ this ->replaceTagToC ($ body );
393+ $ toc_data = $ this ->contentsList ();
394+ $ toc_id = $ this ->getIdAttributeToC ();
395+ $ needle = '<p> ' . $ tag_origin . '</p> ' ;
396+ $ replace = "<div id= \"$ {toc_id}\"> $ {toc_data}</div> " ;
397+
398+ return str_replace ($ needle , $ replace , $ html );
317399 }
318400}
0 commit comments