Completed
Push — master ( 66f74b...403a41 )
by Mikael
04:09
created

CTextFilter::addExcerpt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 1
cts 1
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Mos\TextFilter;
4
5
/**
6
 * Filter and format content.
7
 *
8
 */
9
class CTextFilter
10
{
11
    use TTextUtilities;
12
13
14
15
    /**
16
     * Supported filters.
17
     */
18
    private $filters = [
19
        "jsonfrontmatter",
20
        "yamlfrontmatter",
21
        "bbcode",
22
        "clickable",
23
        "shortcode",
24
        "markdown",
25
        "geshi",
26
        "nl2br",
27
        "purify",
28
        "titlefromh1",
29
        "anchor4Header",
30
     ];
31
32
33
34
     /**
35
      * Current document parsed.
36
      */
37
    private $current;
38
39
40
41
    /**
42
     * Call each filter.
43
     *
44
     * @deprecated deprecated since version 1.2 in favour of parse().
45
     *
46
     * @param string       $text    the text to filter.
47
     * @param string|array $filters as comma separated list of filter,
48
     *                              or filters sent in as array.
49
     *
50
     * @return string the formatted text.
51
     */
52
    public function doFilter($text, $filters)
53
    {
54
        // Define all valid filters with their callback function.
55
        $callbacks = [
56
            'bbcode'    => 'bbcode2html',
57
            'clickable' => 'makeClickable',
58
            'shortcode' => 'shortCode',
59
            'markdown'  => 'markdown',
60
            'nl2br'     => 'nl2br',
61
            'purify'    => 'purify',
62
        ];
63
64
        // Make an array of the comma separated string $filters
65
        if (is_array($filters)) {
66
            $filter = $filters;
67
        } else {
68
            $filters = strtolower($filters);
69
            $filter = preg_replace('/\s/', '', explode(',', $filters));
70
        }
71
72
        // For each filter, call its function with the $text as parameter.
73
        foreach ($filter as $key) {
74
75
            if (!isset($callbacks[$key])) {
76
                throw new Exception("The filter '$filters' is not a valid filter string due to '$key'.");
77
            }
78
            $text = call_user_func_array([$this, $callbacks[$key]], [$text]);
79
        }
80
81
        return $text;
82
    }
83
84
85
86
    /**
87
     * Return an array of all filters supported.
88
     *
89
     * @return array with strings of filters supported.
90
     */
91 1
    public function getFilters()
92
    {
93 1
        return $this->filters;
94
    }
95
96
97
98
    /**
99
     * Check if filter is supported.
100
     *
101
     * @param string $filter to use.
102
     *
103
     * @throws mos/TextFilter/Exception  when filter does not exists.
104
     *
105
     * @return boolean true if filter exists, false othwerwise.
106
     */
107 2
    public function hasFilter($filter)
108
    {
109 2
        return in_array($filter, $this->filters);
110
    }
111
112
113
114
    /**
115
     * Add array items to frontmatter.
116
     *
117
     * @param array|null $matter key value array with items to add
118
     *                           or null if empty.
119
     *
120
     * @return $this
121
     */
122 3
    private function addToFrontmatter($matter)
123
    {
124 3
        if (empty($matter)) {
125 2
            return $this;
126
        }
127
128 2
        if (is_null($this->current->frontmatter)) {
129 2
            $this->current->frontmatter = [];
130 2
        }
131
132 2
        $this->current->frontmatter = array_merge($this->current->frontmatter, $matter);
133 2
        return $this;
134
    }
135
136
137
138
    /**
139
     * Call a specific filter and store its details.
140
     *
141
     * @param string $filter to use.
142
     *
143
     * @throws mos/TextFilter/Exception when filter does not exists.
144
     *
145
     * @return string the formatted text.
146
     */
147 6
    private function parseFactory($filter)
148
    {
149
        // Define single tasks filter with a callback.
150
        $callbacks = [
151 6
            "bbcode"    => "bbcode2html",
152 6
            "clickable" => "makeClickable",
153 6
            "shortcode" => "shortCode",
154 6
            "markdown"  => "markdown",
155 6
            "geshi"     => "syntaxHighlightGeSHi",
156 6
            "nl2br"     => "nl2br",
157 6
            "purify"    => "purify",
158 6
            'anchor4Header' => 'createAnchor4Header',
159 6
        ];
160
161
        // Do the specific filter
162 6
        $text = $this->current->text;
163
        switch ($filter) {
164 6
            case "jsonfrontmatter":
165 3
                $res = $this->jsonFrontMatter($text);
166 3
                $this->current->text = $res["text"];
167 3
                $this->addToFrontmatter($res["frontmatter"]);
168 3
                break;
169
170 4
            case "yamlfrontmatter":
171
                $res = $this->yamlFrontMatter($text);
172
                $this->current->text = $res["text"];
173
                $this->addToFrontmatter($res["frontmatter"]);
174 1
                break;
175
176 4
            case "titlefromh1":
177 2
                $title = $this->getTitleFromFirstH1($text);
178 1
                $this->current->text = $text;
179 1
                if (!isset($this->current->frontmatter["title"])) {
180 1
                    $this->addToFrontmatter(["title" => $title]);
181 1
                }
182 1
                break;
183
184 4
            case "bbcode":
185 4
            case "clickable":
186 4
            case "shortcode":
187 4
            case "markdown":
188 4
            case "geshi":
189 4
            case "nl2br":
190 4
            case "purify":
191 4
            case "anchor4Header":
192 4
                $this->current->text = call_user_func_array(
193 4
                    [$this, $callbacks[$filter]],
194 4
                    [$text]
195 4
                );
196 4
                break;
197
198
            default:
199
                throw new Exception("The filter '$filter' is not a valid filter     string.");
200
        }
201 6
    }
202
203
204
205
    /**
206
     * Call each filter and return array with details of the formatted content.
207
     *
208
     * @param string $text   the text to filter.
209
     * @param array  $filter array of filters to use.
210
     *
211
     * @throws mos/TextFilter/Exception  when filterd does not exists.
212
     *
213
     * @return array with the formatted text and additional details.
214
     */
215 8
    public function parse($text, $filter)
216
    {
217 8
        $this->current = new \stdClass();
218 8
        $this->current->frontmatter = null;
219 8
        $this->current->text = $text;
220
221 8
        foreach ($filter as $key) {
222 6
            $this->parseFactory($key);
223 8
        }
224
225 8
        $this->current->text = $this->getUntilStop($this->current->text);
226 8
227 8
        return $this->current;
228 8
    }
229
230 8
231
232
    /**
233
     * Add excerpt as short version of text if available.
234
     *
235
     * @param object &$current same structure as returned by parse().
236
     *
237
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
238
     */
239
    public function addExcerpt($current)
240
    {
241
        list($excerpt, $hasMore) = $this->getUntilMore($current->text);
242
        $current->excerpt = $excerpt;
243
        $current->hasMore = $hasMore;
244 3
    }
245
246 3
247
248 3
    /**
249
     * Extract front matter from text.
250 3
     *
251
     * @param string $text       the text to be parsed.
252
     * @param string $startToken the start token.
253
     * @param string $stopToken  the stop token.
254
     *
255
     * @return array with the formatted text and the front matter.
256 3
     */
257 3
    private function extractFrontMatter($text, $startToken, $stopToken)
258 3
    {
259
        $tokenLength = strlen($startToken);
260 3
261 2
        $start = strpos($text, $startToken);
262
        // Is a valid start?
263 2
        if ($start !== false && $start !== 0) {
264 2
            if ($text[$start - 1] !== "\n") {
265 2
                $start = false;
266 2
            }
267 3
        }
268
269 3
        $frontmatter = null;
270
        if ($start !== false) {
271
            $stop = strpos($text, $stopToken, $tokenLength - 1);
272
273
            if ($stop !== false && $text[$stop - 1] === "\n") {
274
                $length = $stop - ($start + $tokenLength);
275
276
                $frontmatter = substr($text, $start + $tokenLength, $length);
277
                $textStart = substr($text, 0, $start);
278
                $text = $textStart . substr($text, $stop + $tokenLength);
279
            }
280
        }
281 3
282
        return [$text, $frontmatter];
283 3
    }
284
285 3
286 2
287
    /**
288 2
     * Extract JSON front matter from text.
289
     *
290
     * @param string $text the text to be parsed.
291 2
     *
292
     * @return array with the formatted text and the front matter.
293
     */
294 3
    public function jsonFrontMatter($text)
295
    {
296 3
        list($text, $frontmatter) = $this->extractFrontMatter($text, "{{{\n", "}}}\n");
297
298
        if (!empty($frontmatter)) {
299
            $frontmatter = json_decode($frontmatter, true);
300
301
            if (is_null($frontmatter)) {
302
                throw new Exception("Failed parsing JSON frontmatter.");
303
            }
304
        }
305
306
        return [
307
            "text" => $text,
308
            "frontmatter" => $frontmatter
309
        ];
310
    }
311
312
313
314
    /**
315
     * Extract YAML front matter from text.
316
     *
317
     * @param string $text the text to be parsed.
318
     *
319
     * @return array with the formatted text and the front matter.
320
     */
321
    public function yamlFrontMatter($text)
322
    {
323
        $needle = "---\n";
324
        list($text, $frontmatter) = $this->extractFrontMatter($text, $needle, $needle);
325
326
        if (function_exists("yaml_parse") && !empty($frontmatter)) {
327
            $frontmatter = yaml_parse($needle . $frontmatter);
328
329
            if ($frontmatter === false) {
330
                throw new Exception("Failed parsing YAML frontmatter.");
331
            }
332
        }
333
334
        return [
335
            "text" => $text,
336 1
            "frontmatter" => $frontmatter
337
        ];
338 1
    }
339 1
340
341 1
342 1
    /**
343 1
     * Get the title from the first H1.
344
     *
345 1
     * @param string $text the text to be parsed.
346
     *
347
     * @return string|null with the title, if its found.
348
     */
349
    public function getTitleFromFirstH1($text)
350
    {
351
        $matches = [];
352
        $title = null;
353
354
        if (preg_match("#<h1.*?>(.*)</h1>#", $text, $matches)) {
355
            $title = strip_tags($matches[1]);
356
        }
357
358
        return $title;
359 3
    }
360
361
362 3
363 3
    /**
364 3
     * Helper, BBCode formatting converting to HTML.
365 3
     *
366 3
     * @param string $text The text to be converted.
367
     *
368 3
     * @return string the formatted text.
369
     *
370
     * @link http://dbwebb.se/coachen/reguljara-uttryck-i-php-ger-bbcode-formattering
371 3
     */
372 3
    public function bbcode2html($text)
373 3
    {
374 3
        $search = [
375 3
            '/\[b\](.*?)\[\/b\]/is',
376
            '/\[i\](.*?)\[\/i\]/is',
377 3
            '/\[u\](.*?)\[\/u\]/is',
378
            '/\[img\](https?.*?)\[\/img\]/is',
379 3
            '/\[url\](https?.*?)\[\/url\]/is',
380
            '/\[url=(https?.*?)\](.*?)\[\/url\]/is'
381
        ];
382
383
        $replace = [
384
            '<strong>$1</strong>',
385
            '<em>$1</em>',
386
            '<u>$1</u>',
387
            '<img src="$1" />',
388
            '<a href="$1">$1</a>',
389
            '<a href="$1">$2</a>'
390
        ];
391
392
        return preg_replace($search, $replace, $text);
393 1
    }
394
395 1
396 1
397
    /**
398 1
     * Make clickable links from URLs in text.
399 1
     *
400
     * @param string $text the text that should be formatted.
401 1
     *
402
     * @return string with formatted anchors.
403
     *
404
     * @link http://dbwebb.se/coachen/lat-php-funktion-make-clickable-automatiskt-skapa-klickbara-lankar
405
     */
406
    public function makeClickable($text)
407
    {
408
        return preg_replace_callback(
409
            '#\b(?<![href|src]=[\'"])https?://[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))#',
410
            function ($matches) {
411
                return "<a href='{$matches[0]}'>{$matches[0]}</a>";
412
            },
413
            $text
414 2
        );
415
    }
416 2
417 2
418 2
419 2
    /**
420 2
     * Syntax highlighter using GeSHi http://qbnz.com/highlighter/.
421
     *
422
     * @param string $text     text to be converted.
423
     * @param string $language which language to use for highlighting syntax.
424
     *
425 2
     * @return string the formatted text.
426
     */
427
    public function syntaxHighlightGeSHi($text, $language = "text")
428
    {
429
        $language = $language ?: "text";
430
        $language = ($language === 'html') ? 'html4strict' : $language;
431
        $geshi = new \GeSHi($text, $language);
432
        $geshi->set_overall_class('geshi');
433
        $geshi->enable_classes('geshi');
0 ignored issues
show
Documentation introduced by
'geshi' is of type string, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
434
        //$geshi->set_header_type(GESHI_HEADER_PRE_VALID);
435
        //$geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
436
        //echo "<pre>", $geshi->get_stylesheet(false) , "</pre>"; exit;
437 1
438
        $code = $geshi->parse_code();
439 1
440 1
        // Replace last &nbsp;</pre>, -strlen("&nbsp;</pre>") == 12
441
        $code = substr_replace($code, "</pre>", -12);
442
        return $code;
443 1
    }
444
445 1
446
447
    /**
448
     * Format text according to HTML Purifier.
449
     *
450
     * @param string $text that should be formatted.
451
     *
452
     * @return string as the formatted html-text.
453
     */
454
    public function purify($text)
455
    {
456
        $config   = \HTMLPurifier_Config::createDefault();
457 7
        $config->set("Cache.DefinitionImpl", null);
458
        //$config->set('Cache.SerializerPath', '/home/user/absolute/path');
459 7
460
        $purifier = new \HTMLPurifier($config);
461
    
462
        return $purifier->purify($text);
463
    }
464
465
466
467
    /**
468
     * Format text according to Markdown syntax.
469
     *
470
     * @param string $text the text that should be formatted.
471 1
     *
472
     * @return string as the formatted html-text.
473 1
     */
474
    public function markdown($text)
475
    {
476
        return \Michelf\MarkdownExtra::defaultTransform($text);
477
    }
478
479
480
481
    /**
482
     * For convenience access to nl2br
483
     *
484
     * @param string $text text to be converted.
485 2
     *
486
     * @return string the formatted text.
487
     */
488
    public function nl2br($text)
489
    {
490
        return nl2br($text);
491
    }
492
493
494
495
    /**
496
     * Shortcode to to quicker format text as HTML.
497
     *
498
     * @param string $text text to be converted.
499
     *
500
     * @return string the formatted text.
501 2
     */
502 2
    public function shortCode($text)
503 2
    {
504
        /* Needs PHP 7
505 2
        $patternsAndCallbacks = [
506 2
            "/\[(FIGURE)[\s+](.+)\]/" => function ($match) {
507 2
                return self::ShortCodeFigure($matches[2]);
508 2
            },
509
            "/(```([\w]*))\n([^`]*)```[\n]{1}/s" => function ($match) {
510 2
                return $this->syntaxHighlightGeSHi($matches[3], $matches[2]);
511 1
            },
512
        ];
513
514 1
        return preg_replace_callback_array($patternsAndCallbacks, $text);
515 1
        */
516
517
        $patterns = [
518
            "/\[(FIGURE)[\s+](.+)\]/",
519
            "/(```)([\w]*)\n([^`]*)```[\n]{1}/s",
520
        ];
521 2
522
        return preg_replace_callback(
523 2
            $patterns,
524
            function ($matches) {
525
                switch ($matches[1]) {
526
527
                    case "FIGURE":
528
                        return self::ShortCodeFigure($matches[2]);
529
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
530
531
                    case "```":
532
                        return $this->syntaxHighlightGeSHi($matches[3], $matches[2]);
533
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
534
535 1
                    default:
536
                        return "{$matches[1]} is unknown shortcode.";
537 1
                }
538
            },
539 1
            $text
540 1
        );
541 1
    }
542 1
543
544
545 1
    /**
546 1
     * Init shortcode handling by preparing the option list to an array, for those using arguments.
547 1
     *
548
     * @param string $options for the shortcode.
549 1
     *
550
     * @return array with all the options.
551 1
     */
552
    public static function shortCodeInit($options)
553
    {
554
        preg_match_all('/[a-zA-Z0-9]+="[^"]+"|\S+/', $options, $matches);
555
556
        $res = array();
557
        foreach ($matches[0] as $match) {
558
            $pos = strpos($match, '=');
559
            if ($pos === false) {
560
                $res[$match] = true;
561
            } else {
562
                $key = substr($match, 0, $pos);
563
                $val = trim(substr($match, $pos+1), '"');
564
                $res[$key] = $val;
565 1
            }
566
        }
567
568 1
        return $res;
569
    }
570 1
571 1
572 1
573 1
    /**
574 1
     * Shortcode for <figure>.
575 1
     *
576 1
     * Usage example: [FIGURE src="img/home/me.jpg" caption="Me" alt="Bild på mig" nolink="nolink"]
577 1
     *
578 1
     * @param string $options for the shortcode.
579 1
     *
580 1
     * @return array with all the options.
581 1
     */
582
    public static function shortCodeFigure($options)
583 1
    {
584 1
        // Merge incoming options with default and expose as variables
585 1
        $options= array_merge(
586
            [
587 1
                'id' => null,
588 1
                'class' => null,
589 1
                'src' => null,
590
                'title' => null,
591 1
                'alt' => null,
592 1
                'caption' => null,
593 1
                'href' => null,
594 1
                'nolink' => false,
595
            ],
596 1
            self::ShortCodeInit($options)
597 1
        );
598 1
        extract($options, EXTR_SKIP);
599 1
600 1
        $id = $id ? " id='$id'" : null;
601 1
        $class = $class ? " class='figure $class'" : " class='figure'";
602
        $title = $title ? " title='$title'" : null;
603
604 1
        if (!$alt && $caption) {
605 1
            $alt = $caption;
606 1
        }
607 1
608 1
        if (!$href) {
609
            $pos = strpos($src, '?');
610 1
            $href = $pos ? substr($src, 0, $pos) : $src;
611
        }
612
613
        $start = null;
614
        $end = null;
615
        if (!$nolink) {
616
            $start = "<a href='{$href}'>";
617
            $end = "</a>";
618
        }
619
620
        $html = <<<EOD
621
<figure{$id}{$class}>
622
{$start}<img src='{$src}' alt='{$alt}'{$title}/>{$end}
623
<figcaption markdown=1>{$caption}</figcaption>
624
</figure>
625
EOD;
626
627
        return $html;
628
    }
629
630
631
632
    /**
633
     * Shortcode for [asciinema].
634
     *
635
     * @param string $code the code to process.
636
     * @param string $options for the shortcode.
637
     * @return array with all the options.
638
     */
639
/*    public static function ShortCodeAsciinema($options) {
640
      extract(array_merge(array(
641
        'id' => null,
642
        'class' => null,
643
        'src' => null,
644
        'title' => null,
645
        'alt' => null,
646
        'caption' => null,
647
      ), CTextFilter::ShortCodeInit($options)), EXTR_SKIP);
648
649
      $id = $id ? " id='$id'" : null;
650
      $class = $class ? " class='figure $class'" : " class='figure'";
651
      $title = $title ? " title='$title'" : null;
652
      
653
      if(!$alt && $caption) {
654
        $alt = $caption;
655
      }
656
657
      if(!$href) {
658
        $pos = strpos($src, '?');
659
        $href = $pos ? substr($src, 0, $pos) : $src;
660
      }
661
662
      $html = <<<EOD
663
  <script type="text/javascript" src="https://asciinema.org/a/{$src}.js" id="asciicast-{$src}" async></script>
664
  EOD;
665
666
      return $html;
667
    }
668
*/
669
670
671
672
/**
673
 * Shortcode for including a SVG-image inside a <figure>.
674
 *
675
 * @param string $code the code to process.
676
 * @param string $options for the shortcode.
677
 * @return array with all the options.
678
 */
679
/*public static function ShortCodeSVGFigure($options) {
680
  extract(array_merge(array(
681
    'id' => null,
682
    'class' => null,
683
    'src' => null,
684
    'path' => null,
685
    'title' => null,
686
    'alt' => null,
687
    'caption' => null,
688
    'href' => null,
689
    'nolink' => false,
690
  ), CTextFilter::ShortCodeInit($options)), EXTR_SKIP);
691
692
  $id = $id ? " id='$id'" : null;
693
  //$class = $class ? " class='$class'" : null;
694
  $class = $class ? " class='figure $class'" : " class='figure'";
695
  $title = $title ? " title='$title'" : null;
696
  
697
  if(!$alt && $caption) {
698
    $alt = $caption;
699
  }
700
701
  if(!$href) {
702
    $pos = strpos($src, '?');
703
    $href = $pos ? substr($src, 0, $pos) : $src;
704
  }
705
706
  if(!$nolink) {
707
    $a_start = "<a href='{$href}'>";
708
    $a_end = "</a>";
709
  }
710
711
  // Import the file containing the svg-image
712
  $svg = null;
713
  
714
  if($path[0] != '/') {
715
    $path = self::$dir . '/' . $path;
716
  }
717
718
  if(is_file($path)) {
719
    $svg = file_get_contents($path);
720
  }
721
  else {
722
    $svg = "No such file: $path";
723
  }
724
  $html = <<<EOD
725
<figure{$id}{$class}>
726
{$svg}
727
<figcaption markdown=1>{$caption}</figcaption>
728
</figure>
729
EOD;
730
731
  return $html;
732
}
733
734
*/
735
736
737
738
/**
739
 * Shorttags to to quicker format text as HTML.
740
 *
741
 * @param string text text to be converted.
742
 * @return string the formatted text.
743
 */
744
/*public static function ShortTags($text) {
745
  $callback = function($matches) {
746
    switch($matches[1]) {
747
      case 'IMG':
748
        $caption = t('Image: ');
749
        $pos = strpos($matches[2], '?');
750
        $href = $pos ? substr($matches[2], 0, $pos) : $matches[2];
751
        $src = htmlspecialchars($matches[2]);
752
        return <<<EOD
753
<figure>
754
<a href='{$href}'><img src='{$src}' alt='{$matches[3]}' /></a>
755
<figcaption markdown=1>{$caption}{$matches[3]}</figcaption>
756
</figure>
757
EOD;
758
759
      case 'IMG2':
760
        $caption = null; //t('Image: ');
761
        $pos = strpos($matches[2], '?');
762
        $href = $pos ? substr($matches[2], 0, $pos) : $matches[2];
763
        $src = htmlspecialchars($matches[2]);
764
        return <<<EOD
765
<figure class="{$matches[4]}">
766
<a href='{$href}'><img src='{$src}' alt='{$matches[3]}' /></a>
767
<figcaption markdown=1>{$caption}{$matches[3]}</figcaption>
768
</figure>
769
EOD;
770
      case 'BOOK':
771
        $isbn = $matches[2];
772
        $stores = array(
773
          'BTH' => "http://bth.summon.serialssolutions.com/?#!/search?ho=t&amp;q={$isbn}",
774
          'Libris' => "http://libris.kb.se/hitlist?q={$isbn}",
775
          'Google Books' => "http://books.google.com/books?q={$isbn}",
776
          'Bokus' => "http://www.bokus.com/bok/{$isbn}",
777
          'Adlibris' => "http://www.adlibris.com/se/product.aspx?isbn={$isbn}",
778
          'Amazon' => "http://www.amazon.com/s/ref=nb_ss?url=field-keywords={$isbn}",
779
          'Barnes&Noble' => "http://search.barnesandnoble.com/booksearch/ISBNInquiry.asp?r=1&IF=N&EAN={$isbn}",
780
        );
781
        $html = null;
782
        foreach($stores as $key => $val) {
783
          $html .= "<a href='$val'>$key</a> &bull; ";
784
        }
785
        return substr($html, 0, -8);
786
      break;
787
788
      case 'YOUTUBE':
789
        $caption = t('Figure: ');
790
        $height = ceil($matches[3] / (16/9));
791
        return <<<EOD
792
<figure>
793
<iframe width='{$matches[3]}' height='{$height}' src="http://www.youtube.com/embed/{$matches[2]}" frameborder="0"
794
allowfullscreen></iframe>
795
<figcaption>{$caption}{$matches[4]}</figcaption>
796
</figure>
797
EOD;
798
      break;
799
      
800
      case 'syntax=': return CTextFilter::SyntaxHighlightGeSHi($matches[3], $matches[2]); break;
801
      case '```': return CTextFilter::SyntaxHighlightGeSHi($matches[3], $matches[2]); break;
802
      //case 'syntax=': return "<pre>" . highlight_string($matches[3], true) . "</pre>"; break;
803
      //case 'INCL':  include($matches[2]); break;
804
      case 'INFO':  return "<div class='info' markdown=1>"; break;
805
      case '/INFO': return "</div>"; break;
806
      case 'BASEURL': return CLydia::Instance()->request->base_url; break;
807
      case 'FIGURE': return CTextFilter::ShortCodeFigure($matches[2]); break;
808
      case 'FIGURE-SVG': return CTextFilter::ShortCodeSVGFigure($matches[2]); break;
809
      case 'ASCIINEMA': return CTextFilter::ShortCodeAsciinema($matches[2]); break;
810
      default: return "{$matches[1]} IS UNKNOWN SHORTTAG."; break;
811
    }
812
  };
813
  $patterns = array(
814
    '#\[(BASEURL)\]#',
815
    //'/\[(AUTHOR) name=(.+) email=(.+) url=(.+)\]/',
816
    '/\[(FIGURE)[\s+](.+)\]/',
817
    '/\[(FIGURE-SVG)[\s+](.+)\]/',
818
    '/\[(ASCIINEMA)[\s+](.+)\]/',
819
    '/\[(IMG) src=(.+) alt=(.+)\]/',
820
    '/\[(IMG2) src=(.+) alt="(.+)" class="(.+)"\]/',
821
    '/\[(BOOK) isbn=(.+)\]/',
822
    '/\[(YOUTUBE) src=(.+) width=(.+) caption=(.+)\]/',
823
    '/~~~(syntax=)(php|html|html5|css|sql|javascript|bash)\n([^~]+)\n~~~/s',
824
    '/(```)(php|html|html5|css|sql|javascript|bash|text|txt|python)\n([^`]+)\n```/s',
825
    //'/\[(INCL)/s*([^\]+)/',
826
    '#\[(INFO)\]#', '#\[(/INFO)\]#',
827
  );
828
829
  $ret = preg_replace_callback($patterns, $callback, $text);
830
  return $ret;
831
}
832
*/
833
834
835
836
    /**
837
     * Support SmartyPants for better typography.
838
     *
839
     * @param string text text to be converted.
840
     * @return string the formatted text.
841
     */
842
/*     public static function SmartyPants($text) {   
843
      require_once(__DIR__.'/php_smartypants_1.5.1e/smartypants.php');
844
      return SmartyPants($text);
845
    }
846
*/
847
848
849
    /**
850
     * Support enhanced SmartyPants/Typographer for better typography.
851
     *
852
     * @param string text text to be converted.
853
     * @return string the formatted text.
854
     */
855
/*     public static function Typographer($text) {   
856
      require_once(__DIR__.'/php_smartypants_typographer_1.0/smartypants.php');
857
      $ret = SmartyPants($text);
858
      return $ret;
859
    }
860
*/
861
}
862