Completed
Push — master ( 4dba6c...bdbb24 )
by Mikael
02:08
created

TShortcode::shortCodeInit()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 18
rs 9.4285
cc 3
eloc 12
nc 3
nop 1
1
<?php
2
3
namespace Mos\TextFilter;
4
5
/**
6
 * Shortcode to format when working with text.
7
 *
8
 */
9
trait TShortcode
10
{
11
    /**
12
     * Shortcode to quicker format text as HTML.
13
     *
14
     * @param string $text text to be converted.
15
     *
16
     * @return string the formatted text.
17
     */
18
    public function shortCode($text)
19
    {
20
        /* Needs PHP 7
21
        $patternsAndCallbacks = [
22
            "/\[(FIGURE)[\s+](.+)\]/" => function ($match) {
23
                return self::ShortCodeFigure($matches[2]);
24
            },
25
            "/(```([\w]*))\n([^`]*)```[\n]{1}/s" => function ($match) {
26
                return $this->syntaxHighlightGeSHi($matches[3], $matches[2]);
27
            },
28
        ];
29
30
        return preg_replace_callback_array($patternsAndCallbacks, $text);
31
        */
32
33
        $patterns = [
34
            "/\[(FIGURE)[\s+](.+)\]/",
35
            //'/\[(YOUTUBE) src=(.+) width=(.+) caption=(.+)\]/',
36
            "/\[(YOUTUBE)[\s+](.+)\]/",
37
            "/\[(ASCIINEMA)[\s+](.+)\]/",
38
            "/(```)([\w]*)\n([^`]*)```[\n]{1}/s",
39
            '/\[(INFO)\]/',
40
            '/\[(\/INFO)\]/',
41
        ];
42
43
        return preg_replace_callback(
44
            $patterns,
45
            function ($matches) {
46
                switch ($matches[1]) {
47
48
                    case "FIGURE":
49
                        return self::ShortCodeFigure($matches[2]);
50
                    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...
51
52
                    case "YOUTUBE":
53
                        return self::shortCodeYoutube($matches[2]);
54
                    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...
55
56
                    case "ASCIINEMA":
57
                        return self::ShortCodeAsciinema($matches[2]);
58
                    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...
59
60
                    case "```":
61
                        return $this->syntaxHighlightGeSHi($matches[3], $matches[2]);
0 ignored issues
show
Bug introduced by
It seems like syntaxHighlightGeSHi() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
62
                    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...
63
64
                    case 'INFO':
65
                        return "<div class='info' markdown=1>";
66
                        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...
67
68
                    case '/INFO':
69
                        return "</div>";
70
                        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...
71
72
                    default:
73
                        return "{$matches[1]} is unknown shortcode.";
74
                }
75
            },
76
            $text
77
        );
78
    }
79
80
81
82
    /**
83
     * Init shortcode handling by preparing the option list to an array,
84
     * for those using arguments.
85
     *
86
     * @param string $options for the shortcode.
87
     *
88
     * @return array with all the options.
89
     */
90
    public static function shortCodeInit($options)
91
    {
92
        preg_match_all('/[a-zA-Z0-9]+="[^"]+"|\S+/', $options, $matches);
93
94
        $res = array();
95
        foreach ($matches[0] as $match) {
96
            $pos = strpos($match, '=');
97
            if ($pos === false) {
98
                $res[$match] = true;
99
            } else {
100
                $key = substr($match, 0, $pos);
101
                $val = trim(substr($match, $pos+1), '"');
102
                $res[$key] = $val;
103
            }
104
        }
105
106
        return $res;
107
    }
108
109
110
111
    /**
112
     * Shortcode for [YOUTUBE].
113
     *
114
     * Usage example: [YOUTUBE src=id-for-the-tube width=630 caption=""]
115
     *
116
     * @param string $options for the shortcode.
117
     *
118
     * @return array with all the options.
119
     */
120
    public static function shortCodeYoutube($options)
121
    {
122
        $options= array_merge(
123
            [
124
                "src" => null,
125
                "width" => null,
126
                "caption" => null,
127
                "ratio" => 16/9
128
            ],
129
            self::ShortCodeInit($options)
130
        );
131
        extract($options, EXTR_SKIP);
132
133
        $caption = t("Figure: !CAPTION", ["!CAPTION" => $caption]);
134
        $height = ceil($width / $ratio);
135
136
        $html = <<<EOD
137
<figure>
138
<iframe width="$width" height="$height" src="http://www.youtube.com/embed/$src" frameborder="0" allowfullscreen></iframe>
139
<figcaption markdown=1>{$caption}</figcaption>
140
</figure>
141
EOD;
142
143
        return $html;
144
    }
145
146
147
148
    /**
149
     * Shortcode for <figure>.
150
     *
151
     * Usage example: [FIGURE src="img/home/me.jpg" caption="Me" alt="Bild på mig" nolink="nolink"]
152
     *
153
     * @param string $options for the shortcode.
154
     *
155
     * @return array with all the options.
156
     */
157
    public static function shortCodeFigure($options)
158
    {
159
        // Merge incoming options with default and expose as variables
160
        $options= array_merge(
161
            [
162
                'id' => null,
163
                'class' => null,
164
                'src' => null,
165
                'title' => null,
166
                'alt' => null,
167
                'caption' => null,
168
                'href' => null,
169
                'nolink' => false,
170
            ],
171
            self::ShortCodeInit($options)
172
        );
173
        extract($options, EXTR_SKIP);
174
175
        $id = $id ? " id='$id'" : null;
176
        $class = $class ? " class='figure $class'" : " class='figure'";
177
        $title = $title ? " title='$title'" : null;
178
179
        if (!$alt && $caption) {
180
            $alt = $caption;
181
        }
182
183
        if (!$href) {
184
            $pos = strpos($src, '?');
185
            $href = $pos ? substr($src, 0, $pos) : $src;
186
        }
187
188
        $start = null;
189
        $end = null;
190
        if (!$nolink) {
191
            $start = "<a href='{$href}'>";
192
            $end = "</a>";
193
        }
194
195
        $html = <<<EOD
196
<figure{$id}{$class}>
197
{$start}<img src='{$src}' alt='{$alt}'{$title}/>{$end}
198
<figcaption markdown=1>{$caption}</figcaption>
199
</figure>
200
EOD;
201
202
        return $html;
203
    }
204
205
206
207
    /**
208
     * Shortcode for [asciinema].
209
     *
210
     * @param string $code the code to process.
0 ignored issues
show
Bug introduced by
There is no parameter named $code. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
211
     * @param string $options for the shortcode.
212
     * @return array with all the options.
213
     */
214
    public static function ShortCodeAsciinema($options) {
215
        // Merge incoming options with default and expose as variables
216
        $options= array_merge(
217
            [
218
                'id' => null,
219
                'class' => null,
220
                'src' => null,
221
                'title' => null,
222
                'caption' => null,
223
            ],
224
            self::ShortCodeInit($options)
225
        );
226
        extract($options, EXTR_SKIP);
227
228
        $id = $id ? " id=\"$id\"" : null;
229
        $class = $class ? " class=\"figure asciinema $class\"" : " class=\"figure asciinema\"";
230
        $title = $title ? " title=\"$title\"" : null;
231
232
        $html = <<<EOD
233
<figure{$id}{$class}$title>
234
<script type="text/javascript" src="https://asciinema.org/a/{$src}.js" id="asciicast-{$src}" async></script>
235
<figcaption markdown=1>{$caption}</figcaption>
236
</figure>
237
EOD;
238
239
        return $html;
240
    }
241
242
243
244
/**
245
 * Shortcode for including a SVG-image inside a <figure>.
246
 *
247
 * @param string $code the code to process.
248
 * @param string $options for the shortcode.
249
 * @return array with all the options.
250
 */
251
/*public static function ShortCodeSVGFigure($options) {
252
  extract(array_merge(array(
253
    'id' => null,
254
    'class' => null,
255
    'src' => null,
256
    'path' => null,
257
    'title' => null,
258
    'alt' => null,
259
    'caption' => null,
260
    'href' => null,
261
    'nolink' => false,
262
  ), CTextFilter::ShortCodeInit($options)), EXTR_SKIP);
263
264
  $id = $id ? " id='$id'" : null;
265
  //$class = $class ? " class='$class'" : null;
266
  $class = $class ? " class='figure $class'" : " class='figure'";
267
  $title = $title ? " title='$title'" : null;
268
  
269
  if(!$alt && $caption) {
270
    $alt = $caption;
271
  }
272
273
  if(!$href) {
274
    $pos = strpos($src, '?');
275
    $href = $pos ? substr($src, 0, $pos) : $src;
276
  }
277
278
  if(!$nolink) {
279
    $a_start = "<a href='{$href}'>";
280
    $a_end = "</a>";
281
  }
282
283
  // Import the file containing the svg-image
284
  $svg = null;
285
  
286
  if($path[0] != '/') {
287
    $path = self::$dir . '/' . $path;
288
  }
289
290
  if(is_file($path)) {
291
    $svg = file_get_contents($path);
292
  }
293
  else {
294
    $svg = "No such file: $path";
295
  }
296
  $html = <<<EOD
297
<figure{$id}{$class}>
298
{$svg}
299
<figcaption markdown=1>{$caption}</figcaption>
300
</figure>
301
EOD;
302
303
  return $html;
304
}
305
306
*/
307
308
309
310
/**
311
 * Shorttags to to quicker format text as HTML.
312
 *
313
 * @param string text text to be converted.
314
 * @return string the formatted text.
315
 */
316
/*public static function ShortTags($text) {
317
  $callback = function($matches) {
318
    switch($matches[1]) {
319
      case 'IMG':
320
        $caption = t('Image: ');
321
        $pos = strpos($matches[2], '?');
322
        $href = $pos ? substr($matches[2], 0, $pos) : $matches[2];
323
        $src = htmlspecialchars($matches[2]);
324
        return <<<EOD
325
<figure>
326
<a href='{$href}'><img src='{$src}' alt='{$matches[3]}' /></a>
327
<figcaption markdown=1>{$caption}{$matches[3]}</figcaption>
328
</figure>
329
EOD;
330
331
      case 'IMG2':
332
        $caption = null; //t('Image: ');
333
        $pos = strpos($matches[2], '?');
334
        $href = $pos ? substr($matches[2], 0, $pos) : $matches[2];
335
        $src = htmlspecialchars($matches[2]);
336
        return <<<EOD
337
<figure class="{$matches[4]}">
338
<a href='{$href}'><img src='{$src}' alt='{$matches[3]}' /></a>
339
<figcaption markdown=1>{$caption}{$matches[3]}</figcaption>
340
</figure>
341
EOD;
342
      case 'BOOK':
343
        $isbn = $matches[2];
344
        $stores = array(
345
          'BTH' => "http://bth.summon.serialssolutions.com/?#!/search?ho=t&amp;q={$isbn}",
346
          'Libris' => "http://libris.kb.se/hitlist?q={$isbn}",
347
          'Google Books' => "http://books.google.com/books?q={$isbn}",
348
          'Bokus' => "http://www.bokus.com/bok/{$isbn}",
349
          'Adlibris' => "http://www.adlibris.com/se/product.aspx?isbn={$isbn}",
350
          'Amazon' => "http://www.amazon.com/s/ref=nb_ss?url=field-keywords={$isbn}",
351
          'Barnes&Noble' => "http://search.barnesandnoble.com/booksearch/ISBNInquiry.asp?r=1&IF=N&EAN={$isbn}",
352
        );
353
        $html = null;
354
        foreach($stores as $key => $val) {
355
          $html .= "<a href='$val'>$key</a> &bull; ";
356
        }
357
        return substr($html, 0, -8);
358
      break;
359
360
      case 'YOUTUBE':
361
        $caption = t('Figure: ');
362
        $height = ceil($matches[3] / (16/9));
363
        return <<<EOD
364
<figure>
365
<iframe width='{$matches[3]}' height='{$height}' src="http://www.youtube.com/embed/{$matches[2]}" frameborder="0"
366
allowfullscreen></iframe>
367
<figcaption>{$caption}{$matches[4]}</figcaption>
368
</figure>
369
EOD;
370
      break;
371
      
372
      case 'syntax=': return CTextFilter::SyntaxHighlightGeSHi($matches[3], $matches[2]); break;
373
      case '```': return CTextFilter::SyntaxHighlightGeSHi($matches[3], $matches[2]); break;
374
      //case 'syntax=': return "<pre>" . highlight_string($matches[3], true) . "</pre>"; break;
375
      //case 'INCL':  include($matches[2]); break;
376
      case 'INFO':  return "<div class='info' markdown=1>"; break;
377
      case '/INFO': return "</div>"; break;
378
      case 'BASEURL': return CLydia::Instance()->request->base_url; break;
379
      case 'FIGURE': return CTextFilter::ShortCodeFigure($matches[2]); break;
380
      case 'FIGURE-SVG': return CTextFilter::ShortCodeSVGFigure($matches[2]); break;
381
      case 'ASCIINEMA': return CTextFilter::ShortCodeAsciinema($matches[2]); break;
382
      default: return "{$matches[1]} IS UNKNOWN SHORTTAG."; break;
383
    }
384
  };
385
  $patterns = array(
386
    '#\[(BASEURL)\]#',
387
    //'/\[(AUTHOR) name=(.+) email=(.+) url=(.+)\]/',
388
    '/\[(FIGURE)[\s+](.+)\]/',
389
    '/\[(FIGURE-SVG)[\s+](.+)\]/',
390
    '/\[(ASCIINEMA)[\s+](.+)\]/',
391
    '/\[(IMG) src=(.+) alt=(.+)\]/',
392
    '/\[(IMG2) src=(.+) alt="(.+)" class="(.+)"\]/',
393
    '/\[(BOOK) isbn=(.+)\]/',
394
    '/\[(YOUTUBE) src=(.+) width=(.+) caption=(.+)\]/',
395
    '/~~~(syntax=)(php|html|html5|css|sql|javascript|bash)\n([^~]+)\n~~~/s',
396
    '/(```)(php|html|html5|css|sql|javascript|bash|text|txt|python)\n([^`]+)\n```/s',
397
    //'/\[(INCL)/s*([^\]+)/',
398
    '#\[(INFO)\]#', '#\[(/INFO)\]#',
399
  );
400
401
  $ret = preg_replace_callback($patterns, $callback, $text);
402
  return $ret;
403
}
404
*/
405
}
406