Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BBCode and Markdown wrappers. #5

Merged
merged 4 commits into from
Sep 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ before_script:
script:
- if [[ $DEFAULT == 1 ]]; then vendor/bin/phpunit; fi

- if [[ $CHECKS == 1 ]]; then composer cs-check ; fi
- if [[ $CHECKS == 1 ]]; then composer phpstan-setup && composer phpstan; fi
- if [[ $CHECKS == 1 ]]; then composer cs-check; fi
- if [[ $CHECKS == 1 ]]; then composer stan-setup && composer stan; fi

- if [[ $CODECOVERAGE == 1 ]]; then vendor/bin/phpunit --coverage-clover=clover.xml || true; fi
- if [[ $CODECOVERAGE == 1 ]]; then wget -O codecov.sh https://codecov.io/bash; fi
Expand Down
67 changes: 3 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

A CakePHP plugin to
- easily use code syntax highlighters.
- quickly convert Markdown snippets.
- quickly convert BBCode snippets.

This branch is for **CakePHP 4.0+**. See [version map](https://github.com/dereuromark/cakephp-markup/wiki#cakephp-version-map) for details.

Expand All @@ -25,70 +27,7 @@ https://sandbox.dereuromark.de/sandbox/markup-examples

## Usage

```php
// You must load the helper before
$this->loadHelper('Markup.Highlighter', $optionalConfigArray);

// In our ctp file we can now highlight some code snippet
$string = <<<'TEXT'
$result = 'string' . $this->request->query('key'); // Some comment
TEXT;

echo $this->Highlighter->highlight($string, ['lang' => 'php']);
```

### Supported Highlighters

#### PhpHighlighter
Using native PHP syntax highlighting this default highlighter does not need any dependencies.
Just add some basic CSS styling for all `<pre>` tags.

The output will be automatically escaped (safe) HTML code, e.g. for `php` language code:
```html
<pre class="lang-php"><code>
<span style="color: #000000">$key&nbsp;=&nbsp;'string'&nbsp;.&nbsp;$this-&gt;something-&gt;do(true);&nbsp;//&nbsp;Some&nbsp;comment</span>
</code></pre>
```

#### JsHighlighter
Using only JS via [highlightjs.org](https://highlightjs.org/) or [prismjs.com](http://prismjs.com/) this parser is lightweight on the server side.
It requires a CSS and JS file on top to do client-side highlighting "just in time".
```php
// Helper option
'highlighter' => 'Markup\Highlighter\JsHighlighter',
```

The output for `php` language code will be wrapped in
```html
<pre><code class="language-php">...</code></pre>
```
tags, for example.
Do not forget to add your custom code style CSS file and the JS code as documented at [highlightjs.org](https://highlightjs.org/usage/) or [prismjs.com](http://prismjs.com/#basic-usage).

### Write your own highlighter
You just have to implement the `HighlighterInterface` and ideally extend the abstract `Highlighter` class.
Then you can simply switch your code highlighting on demand or globally with Configure:
```php
// Configure
'Highlighter' => [
'highlighter' => 'VendorName\PluginName\CustomHighlighter',
],
```

You should be able to easily use any custom highlighter this way.

If you are looking for a good auto-detection highlighter, take a look at [github.com/google/code-prettify](https://github.com/google/code-prettify).
In case you need the full options stack, it would be best to write a custom one here, otherwise a basic code template `<pre class="prettyprint">{{content}}</pre>` for `JsHighlighter` should do the trick.

### Additional Configuration
You can switch the template to use `<div>` instead of `<pre`> for example:
```php
// Helper option
'templates' => [
'code' => '<div{{attr}}>{{content}}</div>',
],
```
See [Docs](/docs).

## TODO
- Add more highlighters (you can also just link your own here)
- Add markup parsers and possibly View classes (BBCode, Markdown, ...)
9 changes: 6 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
"cakephp/cakephp": "^4.0.0"
},
"require-dev": {
"fig-r/psr2r-sniffer": "dev-master"
"fig-r/psr2r-sniffer": "dev-master",
"league/commonmark": "^1.5",
"mjohnson/decoda": "^6.12",
"dereuromark/media-embed": "^0.5"
},
"autoload": {
"psr-4": {
Expand All @@ -34,8 +37,8 @@
"source": "https://github.com/dereuromark/cakephp-markup"
},
"scripts": {
"phpstan": "phpstan analyse -c tests/phpstan.neon -l 5 src/",
"phpstan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.12 && mv composer.backup composer.json",
"stan": "phpstan analyse -c tests/phpstan.neon src/",
"stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.12 && mv composer.backup composer.json",
"test": "php phpunit.phar",
"test-setup": "[ ! -f phpunit.phar ] && wget https://phar.phpunit.de/phpunit-8.4.3.phar && mv phpunit-8.4.3.phar phpunit.phar || true",
"test-coverage": "php phpunit.phar --log-junit tmp/coverage/unitreport.xml --coverage-html tmp/coverage --coverage-clover tmp/coverage/coverage.xml",
Expand Down
112 changes: 112 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Documentation

## Highlighter

```php
// You must load the helper before
$this->loadHelper('Markup.Highlighter', $optionalConfigArray);

// In our template file we can now highlight some code snippet
$string = <<<'TEXT'
$result = 'string' . $this->request->query('key'); // Some comment
TEXT;

echo $this->Highlighter->highlight($string, ['lang' => 'php']);
```

### Supported Highlighters

#### PhpHighlighter
Using native PHP syntax highlighting this default highlighter does not need any dependencies.
Just add some basic CSS styling for all `<pre>` tags.

The output will be automatically escaped (safe) HTML code, e.g. for `php` language code:
```html
<pre class="lang-php"><code>
<span style="color: #000000">$key&nbsp;=&nbsp;'string'&nbsp;.&nbsp;$this-&gt;something-&gt;do(true);&nbsp;//&nbsp;Some&nbsp;comment</span>
</code></pre>
```

#### JsHighlighter
Using only JS via [highlightjs.org](https://highlightjs.org/) or [prismjs.com](http://prismjs.com/) this parser is lightweight on the server side.
It requires a CSS and JS file on top to do client-side highlighting "just in time".
```php
// Helper option
'highlighter' => 'Markup\Highlighter\JsHighlighter',
```

The output for `php` language code will be wrapped in
```html
<pre><code class="language-php">...</code></pre>
```
tags, for example.
Do not forget to add your custom code style CSS file and the JS code as documented at [highlightjs.org](https://highlightjs.org/usage/) or [prismjs.com](http://prismjs.com/#basic-usage).

### Write your own highlighter
You just have to implement the `HighlighterInterface` and ideally extend the abstract `Highlighter` class.
Then you can simply switch your code highlighting on demand or globally with Configure:
```php
// Configure
'Highlighter' => [
'highlighter' => 'VendorName\PluginName\CustomHighlighter',
],
```

You should be able to easily use any custom highlighter this way.

If you are looking for a good auto-detection highlighter, take a look at [github.com/google/code-prettify](https://github.com/google/code-prettify).
In case you need the full options stack, it would be best to write a custom one here, otherwise a basic code template `<pre class="prettyprint">{{content}}</pre>` for `JsHighlighter` should do the trick.

### Additional Configuration
You can switch the template to use `<div>` instead of `<pre`> for example:
```php
// Helper option
'templates' => [
'code' => '<div{{attr}}>{{content}}</div>',
],
```

## Markdown

For this you need to decide on a converter library.
By default, the included `CommonMarkMarkdown` class requires you to install its dependency:
```
composer require league/commonmark
```

Once you configured it the way you want it you can start using it.

```php
// You must load the helper before
$this->loadHelper('Markup.Markdown', $optionalConfigArray);

// In our template file we can now convert some markdown code snippet
$string = <<<'TEXT'
Some **bold** text and also some *italic*.
TEXT;

echo $this->Markdown->convert($string);
```


## BBCode

For this you need to decide on a converter library.
By default, the included `DecodaBbcode` class requires you to install its dependency:
```
composer require mjohnson/decoda
```

Once you configured it the way you want it you can start using it.

```php
// You must load the helper before
$this->loadHelper('Markup.Bbcode', $optionalConfigArray);

// In our template file we can now convert some markdown code snippet
$string = <<<'TEXT'
Some [b]bold[/b] text and also some [i]italic[/i].
TEXT;

echo $this->Bbcode->convert($string);
```
19 changes: 19 additions & 0 deletions src/Bbcode/BbcodeInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Markup\Bbcode;

interface BbcodeInterface {

/**
* Convert BBCode markup to HTML.
*
* Options:
* - escape
*
* @param string $text
* @param array $options
* @return string
*/
public function convert(string $text, array $options = []): string;

}
94 changes: 94 additions & 0 deletions src/Bbcode/Decoda/VideoFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace Markup\Bbcode\Decoda;

use Decoda\Decoda;
use Decoda\Filter\AbstractFilter;
use MediaEmbed\MediaEmbed;

class VideoFilter extends AbstractFilter {

/**
* Regex pattern.
*/
public const VIDEO_PATTERN = '/^[-_a-z0-9]+$/is';
public const SIZE_PATTERN = '/^(?:small|medium|large)$/i';

/**
* @var \MediaEmbed\MediaEmbed
*/
protected $MediaEmbed;

/**
* Supported tags.
*
* @var array
*/
protected $_tags = [
'video' => [
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => [
'default' => self::ALPHA,
'size' => self::SIZE_PATTERN,
],
],
];

/**
* Custom build the HTML for videos.
*
* @param array $tag
* @param string $content
* @return string
*/
public function parse(array $tag, $content) {
$provider = isset($tag['attributes']['default']) ? $tag['attributes']['default'] : $tag['tag'];
//$size = mb_strtolower(isset($tag['attributes']['size']) ? $tag['attributes']['size'] : 'medium');

preg_match('/^\[video\s*=\s*([a-z0-9_-]+)\]$/i', $tag['text'], $matches);
if (!$matches) {
return $tag['text'] . $content . '[/' . $tag['tag'] . ']';
}

$provider = $matches[1];
$result = $this->transform($provider, $content);
if (!$result) {
return $tag['text'] . $content . '[/' . $tag['tag'] . ']';
}

return $result;
}

/**
* @param string $provider
* @param string $id
*
* @return string|null
*/
protected function transform($provider, $id) {
// timestamp?
if (strpos($id, ',') !== false) {
[$id, $t] = explode(',', $id, 2);
}
if (!empty($t)) {
// with timestamps we cannot use the embed mode...
//TODO
}

if (!isset($this->MediaEmbed)) {
$this->MediaEmbed = new MediaEmbed();
}
$MediaObject = $this->MediaEmbed->parseId($id, $provider);
if (!$MediaObject) {
return null;
}

$MediaObject->setAttribute('width', '100%');

return $MediaObject->getEmbedCode();
}

}
Loading