1: <?php
2:
3: AlphaAutoLoader::loadLib('markdown.php');
4:
5: /**
6: *
7: * A custom version of the markdown class which uses the geshi library for rendering code
8: *
9: * @package alpha::util
10: * @since 1.0
11: * @author John Collins <dev@alphaframework.org>
12: * @version $Id: AlphaMarkdown.inc 1624 2012-12-21 12:17:55Z alphadevx $
13: * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
14: * @copyright Copyright (c) 2012, John Collins (founder of Alpha Framework).
15: * All rights reserved.
16: *
17: * <pre>
18: * Redistribution and use in source and binary forms, with or
19: * without modification, are permitted provided that the
20: * following conditions are met:
21: *
22: * * Redistributions of source code must retain the above
23: * copyright notice, this list of conditions and the
24: * following disclaimer.
25: * * Redistributions in binary form must reproduce the above
26: * copyright notice, this list of conditions and the
27: * following disclaimer in the documentation and/or other
28: * materials provided with the distribution.
29: * * Neither the name of the Alpha Framework nor the names
30: * of its contributors may be used to endorse or promote
31: * products derived from this software without specific
32: * prior written permission.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
35: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
36: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
39: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47: * </pre>
48: *
49: */
50: class AlphaMarkdown extends MarkdownExtra_Parser {
51:
52: /**
53: * Custom version of the _doCodeBlocks_callback method which invokes a Gheshi
54: * object to render code.
55: *
56: * @since 1.0
57: */
58: public function _doCodeBlocks_callback($matches) {
59: global $config;
60:
61: $codeblock = $matches[1];
62:
63: $codeblock = $this->outdent($codeblock);
64:
65: // trim leading newlines and trailing whitespace
66: $codeblock = preg_replace(array('/\A\n+/', '/\n+\z/'), '', $codeblock);
67:
68: // find the code block and replace it with a blank
69: $codeTypeTag = array();
70: preg_match('/codeType=\[.*\]/', $codeblock, $codeTypeTag);
71: $codeblock = preg_replace('/codeType=\[.*\]\n/', '', $codeblock);
72:
73: if(isset($codeTypeTag[0])) {
74: $start = strpos($codeTypeTag[0], '[');
75: $end = strpos($codeTypeTag[0], ']');
76: $language = substr($codeTypeTag[0], $start+1, $end-($start+1));
77: }else{
78: // will use php as a defualt language type when none is provided
79: $language = 'php';
80: }
81:
82: if($config->get('cms.highlight.provider.name') != '') {
83: $highlighter = AlphaHighlightProviderFactory::getInstance($config->get('cms.highlight.provider.name'));
84: $codeblock = $highlighter->highlight($codeblock, $language);
85: }
86:
87: $result = "\n\n".$this->hashBlock("<pre><code>" . $codeblock . "\n</code></pre>")."\n\n";
88:
89: return $result;
90: }
91:
92: /**
93: * Custom _doAnchors_inline_callback that renders links to external sites with a
94: * target attribute and an icon.
95: *
96: * @since 1.0
97: */
98: public function _doAnchors_inline_callback($matches) {
99: global $config;
100:
101: $whole_match = $matches[1];
102: $link_text = $this->runSpanGamut($matches[2]);
103: $url = $matches[3];
104: $title =& $matches[6];
105:
106: $external = false;
107:
108: $parts = parse_url($url);
109:
110: /*
111: * Only an external link if:
112: *
113: * 1. $url parses to a valid URL
114: * 2. $url has a host part
115: * 3. $url does not contain $config->get('app.url'), i.e. points to a local resource.
116: */
117: if(is_array($parts) && isset($parts['host']) && strpos($url, $config->get('app.url')) === false)
118: $external = true;
119:
120: $url = $this->encodeAmpsAndAngles($url);
121:
122: $result = "<a href=\"$url\"";
123: if (isset($title)) {
124: $title = str_replace('"', '"', $title);
125: $title = $this->encodeAmpsAndAngles($title);
126: $result .= " title=\"$title\"";
127: }
128: if ($external) {
129: $result .= " target=\"$url\"";
130: }
131:
132: $link_text = $this->runSpanGamut($link_text);
133: if (!$external) {
134: $result .= ">$link_text</a>";
135: }else{
136: $result .= '>'.$link_text.'<img src="'.$config->get('app.url').'alpha/images/icons/page_go.png'.'" class="externalLink"/></a>';
137: }
138:
139: return $this->hashSpan($result);
140: }
141:
142: /**
143: * Custom version of the _doTable_callback(...) method which sets the table border and CSS style
144: *
145: * @since 1.0
146: */
147: public function _doTable_callback($matches) {
148: $head = $matches[1];
149: $underline = $matches[2];
150: $content = $matches[3];
151:
152: # Remove any tailing pipes for each line.
153: $head = preg_replace('/[|] *$/m', '', $head);
154: $underline = preg_replace('/[|] *$/m', '', $underline);
155: $content = preg_replace('/[|] *$/m', '', $content);
156:
157: # Reading alignement from header underline.
158: $separators = preg_split('/ *[|] */', $underline);
159: foreach ($separators as $n => $s) {
160: if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"';
161: else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
162: else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
163: else $attr[$n] = '';
164: }
165:
166: # Creating code spans before splitting the row is an easy way to
167: # handle a code span containg pipes.
168: $head = $this->doCodeSpans($head);
169: $headers = preg_split('/ *[|] */', $head);
170: $col_count = count($headers);
171:
172: # Write column headers.
173: $text = "<table class=\"bordered\" border=\"1\">\n";
174: $text .= "<thead>\n";
175: $text .= "<tr>\n";
176: foreach ($headers as $n => $header)
177: $text .= " <th$attr[$n]>".$this->runSpanGamut(trim($header))."</th>\n";
178: $text .= "</tr>\n";
179: $text .= "</thead>\n";
180:
181: # Split content by row.
182: $rows = explode("\n", trim($content, "\n"));
183:
184: $text .= "<tbody>\n";
185: foreach ($rows as $row) {
186: # Creating code spans before splitting the row is an easy way to
187: # handle a code span containg pipes.
188: $row = $this->doCodeSpans($row);
189:
190: # Split row by cell.
191: $row_cells = preg_split('/ *[|] */', $row, $col_count);
192: $row_cells = array_pad($row_cells, $col_count, '');
193:
194: $text .= "<tr>\n";
195: foreach ($row_cells as $n => $cell)
196: $text .= " <td$attr[$n]>".$this->runSpanGamut(trim($cell))."</td>\n";
197: $text .= "</tr>\n";
198: }
199: $text .= "</tbody>\n";
200: $text .= "</table>";
201:
202: return $this->hashBlock($text) . "\n";
203: }
204: }
205:
206: ?>