Procházet zdrojové kódy

Add working bbcode parsing

staging
rodič
revize
b3956472ac
27 změnil soubory, kde provedl 506 přidání a 926 odebrání
  1. +23
    -0
      app/BbCode/Tag/Blockquote.php
  2. +24
    -0
      app/BbCode/Tag/Bold.php
  3. +24
    -0
      app/BbCode/Tag/HeadingOne.php
  4. +24
    -0
      app/BbCode/Tag/HeadingTwo.php
  5. +31
    -0
      app/BbCode/Tag/Image.php
  6. +24
    -0
      app/BbCode/Tag/Italic.php
  7. +35
    -0
      app/BbCode/Tag/Link.php
  8. +32
    -0
      app/BbCode/Tag/Quote.php
  9. +24
    -0
      app/BbCode/Tag/Spoiler.php
  10. +24
    -0
      app/BbCode/Tag/Strikethrough.php
  11. +27
    -0
      app/BbCode/Tag/Text.php
  12. +26
    -0
      app/BbCode/Tag/Twitter.php
  13. +24
    -0
      app/BbCode/Tag/Underline.php
  14. +32
    -0
      app/BbCode/Tag/Unknown.php
  15. +83
    -101
      app/Helper/BBCode.php
  16. +2
    -0
      app/Knockout/Post.php
  17. +1
    -1
      app/Knockout/Thread.php
  18. +0
    -333
      app/Vendor/BBCode/BBCode.php
  19. +0
    -21
      app/Vendor/BBCode/LICENSE
  20. +0
    -67
      app/Vendor/BBCode/Tag.php
  21. +0
    -32
      app/Vendor/BBCode/Tag/AbstractTag.php
  22. +0
    -169
      app/Vendor/BBCode/Tokenizer/Token.php
  23. +0
    -149
      app/Vendor/BBCode/Tokenizer/Tokenizer.php
  24. +8
    -1
      composer.json
  25. +31
    -51
      composer.lock
  26. +6
    -0
      resources/views/partial/bbcode/quote.blade.php
  27. +1
    -1
      resources/views/partial/post.blade.php

+ 23
- 0
app/BbCode/Tag/Blockquote.php Zobrazit soubor

@@ -0,0 +1,23 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class Blockquote extends SimpleTag
{
public function getCloseHtmlTag() : string
{
return '</div>';
}

public function getOpenHtmlTag() : string
{
return '<div class="blockquote">';
}

public function getTag(): string
{
return 'blockquote';
}
}

+ 24
- 0
app/BbCode/Tag/Bold.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class Bold extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</b>';
}

public function getOpenHtmlTag(): string
{
return '<b>';
}

public function getTag() : string
{
return 'b';
}
}

+ 24
- 0
app/BbCode/Tag/HeadingOne.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class HeadingOne extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</h1>';
}

public function getOpenHtmlTag(): string
{
return '<h1>';
}

public function getTag() : string
{
return 'h1';
}
}

+ 24
- 0
app/BbCode/Tag/HeadingTwo.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class HeadingTwo extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</h2>';
}

public function getOpenHtmlTag(): string
{
return '<h2>';
}

public function getTag() : string
{
return 'h2';
}
}

+ 31
- 0
app/BbCode/Tag/Image.php Zobrazit soubor

@@ -0,0 +1,31 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\TagInterface;
use Knockout\BbCode\Tokenizer\Tag as TokenTag;

class Image implements TagInterface
{

public function format(TokenTag $tokenTag): string
{
$link = $tokenTag->getText();
if (!preg_match('!^https?://[a-z0-9\-@:.,_&+%#?/=]+$!i', $link)) {
$unknownTag = new UnknownSimpleType();
return $unknownTag->format($tokenTag);
}

return '<img src="' . $link . '" />';
}

public function getName(): string
{
return 'img';
}

public function getOriginalText(TokenTag $tokenTag): string
{
return "[{$this->getName()}]{$tokenTag->getText()}[/{$this->getName()}";
}
}

+ 24
- 0
app/BbCode/Tag/Italic.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class Italic extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</em>';
}

public function getOpenHtmlTag(): string
{
return '<em>';
}

public function getTag() : string
{
return 'i';
}
}

+ 35
- 0
app/BbCode/Tag/Link.php Zobrazit soubor

@@ -0,0 +1,35 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\TagInterface;
use Knockout\BbCode\Tokenizer\Tag as TokenTag;

class Link implements TagInterface
{

const REG_EXP_VALID_URL = '~https?://[a-zA-Z0-9_\-.:/#?]+~';

public function format(TokenTag $tokenTag): string
{
$args = $tokenTag->parseArgument();
$url = $args['href'] ?? null;

if (!preg_match(self::REG_EXP_VALID_URL, $url)) {
$simpleTag = new Unknown();
return $simpleTag->format($tokenTag);
}

return "<a href=\"{$url}\" target=\"_blank\">{$tokenTag->getText()}</a>";
}

public function getName(): string
{
return 'url';
}

public function getOriginalText(TokenTag $tokenTag) : string
{
return "[url={$tokenTag->getArgument()}]{$tokenTag->getText()}[/url]";
}
}

+ 32
- 0
app/BbCode/Tag/Quote.php Zobrazit soubor

@@ -0,0 +1,32 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\TagInterface;
use Knockout\BbCode\Tokenizer\Tag as TokenTag;

class Quote implements TagInterface
{

public function format(TokenTag $tokenTag): string
{
$attrs = $tokenTag->parseArgument();
return view('partial/bbcode/quote', [
'thread' => $attrs->threadId ?? 1,
'page' => $attrs->threadPage ?? 1,
'postId' => $attrs->postId ?? 1,
'username' => $attrs->username ?? 'Unknown',
'content' => $tokenTag->getText()
]);
}

public function getName(): string
{
return 'quote';
}

public function getOriginalText(TokenTag $tokenTag): string
{
return "[{$this->getName()}]{$tokenTag->getText()}[/{$this->getName()}";
}
}

+ 24
- 0
app/BbCode/Tag/Spoiler.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class Spoiler extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</span>';
}

public function getOpenHtmlTag(): string
{
return '<span class="spoiler">';
}

public function getTag() : string
{
return 'spoiler';
}
}

+ 24
- 0
app/BbCode/Tag/Strikethrough.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class Strikethrough extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</s>';
}

public function getOpenHtmlTag(): string
{
return '<s>';
}

public function getTag() : string
{
return 's';
}
}

+ 27
- 0
app/BbCode/Tag/Text.php Zobrazit soubor

@@ -0,0 +1,27 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\TagInterface;
use Knockout\BbCode\Tokenizer\Tag as TokenTag;

class Text implements TagInterface
{

public function format(TokenTag $tokenTag) : string
{
$formattedString = "{$tokenTag->getText()}";
return $formattedString;
}

public function getName(): string
{
return '';
}

public function getOriginalText(TokenTag $tokenTag): string
{
// there is nothing special
return $this->format($tokenTag);
}
}

+ 26
- 0
app/BbCode/Tag/Twitter.php Zobrazit soubor

@@ -0,0 +1,26 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\TagInterface;
use Knockout\BbCode\Tokenizer\Tag as TokenTag;

class Twitter implements TagInterface
{

public function format(TokenTag $tokenTag): string
{
$url = $tokenTag->getText();
return "<a href=\"{$url}\" target=\"_blank\">[Twitter Embed]</a>";
}

public function getName(): string
{
return 'twitter';
}

public function getOriginalText(TokenTag $tokenTag) : string
{
return "[twitter]{$tokenTag->getText()}[/twitter]";
}
}

+ 24
- 0
app/BbCode/Tag/Underline.php Zobrazit soubor

@@ -0,0 +1,24 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\SimpleTag;

class Underline extends SimpleTag
{

public function getCloseHtmlTag(): string
{
return '</u>';
}

public function getOpenHtmlTag(): string
{
return '<u>';
}

public function getTag() : string
{
return 'u';
}
}

+ 32
- 0
app/BbCode/Tag/Unknown.php Zobrazit soubor

@@ -0,0 +1,32 @@
<?php

namespace App\BbCode\Tag;

use Knockout\BbCode\Tag\TagInterface;
use Knockout\BbCode\Tokenizer\Tag as TokenTag;

class Unknown implements TagInterface
{

public function format(TokenTag $tokenTag) : string
{
$formattedString = "[{$tokenTag->getType()}";

if ($tokenTag->getArgument()) {
$formattedString .= "={$tokenTag->getArgument()}";
}

$formattedString .= "]{$tokenTag->getText()}[/{$tokenTag->getType()}]";
return $formattedString;
}

public function getName(): string
{
return '';
}

public function getOriginalText(TokenTag $tokenTag): string
{
return "[{$tokenTag->getType()}]{$tokenTag->getText()}[/{$tokenTag->getType()}]";
}
}

+ 83
- 101
app/Helper/BBCode.php Zobrazit soubor

@@ -1,118 +1,100 @@
<?php

namespace App\Helper;
use App\Vendor\BBCode\BBCode as Parser;

//use ChrisKonnertz\BBCode\BBCode as Parser;
use App\BbCode\Tag\Unknown;
use App\BbCode\Tag\Text;
use App\BbCode\Tag\Bold;
use App\BbCode\Tag\Italic;
use App\BbCode\Tag\Underline;
use App\BbCode\Tag\Strikethrough;
use App\BbCode\Tag\Spoiler;
use App\BbCode\Tag\HeadingOne;
use App\BbCode\Tag\HeadingTwo;
use App\BbCode\Tag\Link;
use App\BbCode\Tag\Image;
use App\BbCode\Tag\Quote;
use App\BbCode\Tag\Blockquote;
use App\BbCode\Tag\Twitter;

use Knockout\BbCode\BbCode as Parser;
use Knockout\BbCode\Tokenizer\Tokenizer;

class BBCode {

private $parser;
private $content;
private $tokens;

public function __construct($content)
{
$this->parser = new Parser();
$this->content = $content;
//$this->defineTags();
}

private function defineTags()
{
// bold
$this->parser->addTag('b', function($tag, &$html, $openingTag) {
return $openingTag ? '<strong>' : '</strong>';
});

// italics
$this->parser->addTag('i', function($tag, &$html, $openingTag) {
return $openingTag ? '<em>' : '</em>';
});

// underline
$this->parser->addTag('u', function($tag, &$html, $openingTag) {
return $openingTag ? '<u>' : '</u>';
});

// strikethrough
$this->parser->addTag('s', function($tag, &$html, $openingTag) {
return $openingTag ? '<s>' : '</s>';
});

// spoiler
$this->parser->addTag('spoiler', function($tag, &$html, $openingTag) {
return $openingTag ? '<span class="spoiler">' : '</span>';
});

// heading 1
$this->parser->addTag('h1', function($tag, &$html, $openingTag) {
return $openingTag ? '<h1>' : '</h1>';
});

// heading 2
$this->parser->addTag('h2', function($tag, &$html, $openingTag) {
return $openingTag ? '<h2>' : '</h2>';
});

// hyperlink
$this->parser->addTag('url', function($tag, &$html, $openingTag) {
if (!$openingTag) return '</a>';
return sprintf('<a href="%s">', $tag->property ?? $html);
});

// blockquote
$this->parser->addTag('blockquote', function($tag, &$html, $openingTag) {
return $openingTag ? '<div class="blockquote">' : '</div>';
});

// code
$this->parser->addTag('code', function($tag, &$html, $openingTag) {
return $openingTag ? '<pre>' : '</pre>';
});

// unordered list
$this->parser->addTag('ul', function($tag, &$html, $openingTag) {
return $openingTag ? '<ul>' : '</ul>';
});

// ordered list
$this->parser->addTag('ol', function($tag, &$html, $openingTag) {
return $openingTag ? '<ol>' : '</ol>';
});

// list item
$this->parser->addTag('li', function($tag, &$html, $openingTag) {
return $openingTag ? '<li>' : '</li>';
});

// quote
$this->parser->addTag('quote', function($tag, &$html, $openingTag) {
return $this->renderQuote($tag, $html, $openingTag);
});

// quote shorthand
$this->parser->addTag('q', function($tag, &$html, $openingTag) {
return $this->renderQuote($tag, $html, $openingTag);
});

}

public function renderQuote($tag, &$html, $openingTag)
{
exit('kek');
if (!$openingTag) return '</div></div>';
return '<div class="quote"><a class="user" href="#">User</a><div class="postContent">';
// '<div class="quote"><a class="user" href="/thread/%d/%d#post-%d">%s</a><div class="postContent">',
// $postData->threadId,
// $postData->threadPage,
// $postData->postId,
// $postData->username
$this->tokens = (new Tokenizer())->tokenize($content);
}

public function render()
{
//$test = '[quote mentionsUser="1427" postId="659032" threadPage="1" threadId="19764" username="Dr. Magnusson"][/quote]';
return $this->parser->renderPlain($this->content);
$parser = new Parser();

$unknown = new Unknown();
$parser->addTag($unknown);

$text = new Text();
$parser->addTag($text);

$bold = new Bold();
$parser->addTag($bold);

$italic = new Italic();
$parser->addTag($italic);

$underline = new Underline();
$parser->addTag($underline);

$strikethrough = new Strikethrough();
$parser->addTag($strikethrough);

$image = new Image();
$parser->addTag($image);

$link = new Link();
$parser->addTag($link);

$quote = new Quote();
$parser->addTag($quote);

$blockquote = new Blockquote();
$parser->addTag($blockquote);

$twitter = new Twitter();
$parser->addTag($twitter);

$tags = [
$unknown,
$text,
$bold,
$italic,
$underline,
$strikethrough,
$image,
$link,
$quote,
$blockquote,
$twitter
];

$anyChild = [
$bold,
$quote,
$blockquote,
$text,
$unknown
];

foreach ($anyChild as $parent) {
foreach ($tags as $tag) {
$parser->addAllowedChildTag($parent, $tag);
}
}

return $parser->format($this->tokens);
}

}

+ 2
- 0
app/Knockout/Post.php Zobrazit soubor

@@ -23,6 +23,8 @@ class Post {
$s->date = Carbon::parse($post->createdAt)->format('d/m/Y H:i');
$s->content = $post->content;

//$s->content = '[quote mentionsUser="1427" postId="659032" threadPage="1" threadId="19764" username="Dr. Magnusson"][/quote]';

// grab user if available
if (isset($post->user)) {
$s->user = User::unwrap($post->user);


+ 1
- 1
app/Knockout/Thread.php Zobrazit soubor

@@ -139,7 +139,7 @@ class Thread {
return (new Dataset($record))
->setTotalRecords($json->totalPosts)
->setCurrentPage($json->currentPage)
->setRecordsPerPage(40);
->setRecordsPerPage(20);
}

public static function updateOne(int $subforumId, int $page = 1): Dataset


+ 0
- 333
app/Vendor/BBCode/BBCode.php Zobrazit soubor

@@ -1,333 +0,0 @@
<?php

namespace App\Vendor\BBCode;

use App\Vendor\BBCode\Tags\BoldTag;
use App\Vendor\BBCode\Tags\NoParseTag;
use App\Vendor\BBCode\Tokenizer\Token;
use App\Vendor\BBCode\Tokenizer\Tokenizer;
use Closure;

/*
* BBCode to HTML converter
*
* Inspired by Kai Mallea (kmallea@gmail.com)
*
* Licensed under the MIT license:
* http://www.opensource.org/licenses/mit-license.php
*/
class Bbcode {

protected $tagTypes = [];

/**
* The text with BBCodes
*
* @var string|null
*/
protected $text = null;

/**
* BBCode constructor.
*
* @param string|null $text The text - might include BBCode tags
*/
public function __construct($text = null)
{
$this->setText($text);
}

/**
* Set the raw text - might include BBCode tags
*
* @param string $text The text
* @retun void
*/
public function setText($text)
{
$this->text = $text;
}

/**
* Renders only the text without any BBCode tags.
*
* @param string $text Optional: Render the passed BBCode string instead of the internally stored one
* @return string
*/
public function renderPlain($text = null)
{
if ($this->text !== null and $text === null) {
$text = $this->text;
}

return preg_replace("/\[(.*?)\]/is", '', $text);
}

/**
* Renders only the text without any BBCode tags.
* Alias for renderRaw().
*
* @deprecated Deprecated since 1.1.0
*
* @param string $text Optional: Render the passed BBCode string instead of the internally stored one
* @return string
*/
public function renderRaw($text = null)
{
return $this->renderPlain($text);
}

/**
* Renders BBCode to HTML
*
* @param string $text Optional: Render the passed BBCode string instead of the internally stored one
* @param bool $escape Escape HTML entities? (Only "<" and ">"!)
* @param bool $keepLines Keep line breaks by replacing them with <br>?
* @return string
*/
public function render($text = null, $escape = true, $keepLines = true)
{
if ($this->text !== null and $text === null) {
$text = $this->text;
}

$tokenizer = new Tokenizer($this->tagTypes);
$tokens = $tokenizer->tokenize($text, $escape, $keepLines);

$html = '';
$level = 0;
foreach ($tokens as $index => $token) {
switch ($token->getType()) {
case Token::TYPE_LINEBREAK:
$html .= '<br/>';
break;
case Token::TYPE_PLAIN_TEXT:
$html .= $token->getValue();
break;
case Token::TYPE_TAG_OPENING:
case Token::TYPE_TAG_CLOSING:
$tagOpening = $token->getType() === Token::TYPE_TAG_OPENING;
$tagName = $token->getValue();

// If the tag is not known, just do not render it. We do not want to throw any exceptions.
if (isset($this->tagTypes[$tagName])) {
$tagType = $this->tagTypes[$tagName];

/** @var AbstractTagType $tag */
$tag = new $tagType;
$tag->render($html, $tagOpening);
}


if ($tagOpening) {
$level++;
} else {
$level--;
}
}
}

return $html;


$html = '';
$len = mb_strlen($text);
$inTag = false; // True if current position is inside a tag
$inName = false; // True if current pos is inside a tag name
$inStr = false; // True if current pos is inside a string
/** @var Tag|null $tag */
$tag = null;
$openTags = array();

/*
* Loop over each character of the text
*/
for ($i = 0; $i < $len; $i++) {
$char = mb_substr($text, $i, 1);

if ($keepLines) {
if ($char == "\n") {
$html .= '<br/>';
}
if ($char == "\r") {
continue;
}
}

if (! $escape or ($char != '<' and $char != '>')) {
/*
* $inTag == true means the current position is inside a tag definition
* (= inside the brackets of a tag)
*/
if ($inTag) {
if ($char == '"') {
if ($inStr) {
$inStr = false;
} else {
if ($inName) {
$tag->valid = false;
} else {
$inStr = true;
}
}
} else {
/*
* This closes a tag
*/
if ($char == ']' and ! $inStr) {
$inTag = false;
$inName = false;

if ($tag->valid) {
$code = null;

if ($tag->opening) {
$code = $this->generateTag($tag, $html, null, $openTags);
} else {
$openingTag = $this->popTag($openTags, $tag);
if ($openingTag) {
$code = $this->generateTag($tag, $html, $openingTag, $openTags);
}
}

if ($code !== null and $tag->opening) {
$openTags[$tag->name][] = $tag;
}

$html .= $code;
}
continue;
}

if ($inName and ! $inStr) {
/*
* This makes the current tag a closing tag
*/
if ($char == '/') {
if ($tag->name) {
$tag->valid = false;
} else {
$tag->opening = false;
}
} else {
/*
* This means a property starts
*/
if ($char == '=') {
if ($tag->name) {
$inName = false;
} else {
$tag->valid = false;
}
} else {
$tag->name .= mb_strtolower($char);
}
}
} else { // If we are not inside the name we are inside a property
$tag->property .= $char;
}
}
} else {
/*
* This opens a tag
*/
if ($char == '[') {
$inTag = true;
$inName = true;
$tag = new Tag();
$tag->position = mb_strlen($html);
} else {
$html .= $char;
}
}
} else {
$html .= htmlspecialchars($char);
}
}

/*
* Check for tags that are not closed and close them.
*/
foreach ($openTags as $name => $openTagsByType) {
$closingTag = new Tag($name, false);

foreach ($openTagsByType as $openTag) {
$html .= $this->generateTag($closingTag, $html, $openTag);
}
}

return $html;
}

/**
* Generates and returns the HTML code of the current tag
*
* @param Tag $tag The current tag
* @param string $html The current HTML code passed by reference - might be altered!
* @param Tag|null $openingTag The opening tag that is linked to the tag (or null)
* @param Tag[] $openTags Array with tags that are opned but not closed
* @return string
*/
protected function generateTag(Tag $tag, &$html, Tag $openingTag = null, array $openTags = [])
{
$code = null;

if (in_array($tag->name, $this->ignoredTags)) {
return $code;
}

// Custom tags:
foreach ($this->customTagClosures as $name => $closure) {
if ($tag->name === $name) {
exit($tag->name);
$code .= $closure($tag, $html, $openingTag);
}
}

return $code;
}

/**
* Magic method __toString()
*
* @return string
*/
public function __toString()
{
return $this->render();
}

/**
* Returns the last tag of a given type and removes it from the array.
*
* @param Tag[] $tags Array of tags
* @param Tag $tag Return the last tag of the type of this tag
* @return Tag|null
*/
protected function popTag(array &$tags, $tag)
{
if (! isset($tags[$tag->name])) {
return null;
}

$size = sizeof($tags[$tag->name]);

if ($size === 0) {
return null;
} else {
return array_pop($tags[$tag->name]);
}
}

/**
* Returns true if $haystack ends with $needle
*
* @param string $haystack
* @param string $needle
* @return bool
*/
protected function endsWith($haystack, $needle)
{
return ($needle === '' or mb_substr($haystack, -mb_strlen($needle)) === $needle);
}
}

+ 0
- 21
app/Vendor/BBCode/LICENSE Zobrazit soubor

@@ -1,21 +0,0 @@
MIT License

Copyright (c) 2017 Chris Konnertz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 0
- 67
app/Vendor/BBCode/Tag.php Zobrazit soubor

@@ -1,67 +0,0 @@
<?php

namespace App\Vendor\BBCode;

/**
* This class represents a single BBCode tag.
* It is just a simple class used for storing tag.
*
* @package ChrisKonnertz\BBCode
*/
class Tag {

/**
* The name of the tag
*
* @var string|null
*/
public $name = null;

/**
* The value of the property
*
* @var string
*/
public $property = null;

/**
* Is this an opening tag (true)?
*
* @var bool
*/
public $opening = true;

/**
* Is this tag valid?
*
* @var bool
*/
public $valid = true;

/**
* Position of this tag inside the whole BBCode string
*
* @var int
*/
public $position = -1;

/**
* Tag constructor.
*
* @param string|null $name The name of the tag
* @param bool $opening Is this an opening tag (true)?
*/
public function __construct($name = null, $opening = true)
{
if ($name !== null and ! is_string($name)) {
throw new \InvalidArgumentException('The "name" parameter has to be of type string');
}
if (! is_bool($opening)) {
throw new \InvalidArgumentException('The "opening" parameter has to be of type bool');
}

$this->name = $name;
$this->opening = $opening;
}

}

+ 0
- 32
app/Vendor/BBCode/Tag/AbstractTag.php Zobrazit soubor

@@ -1,32 +0,0 @@
<?php

namespace App\Vendor\BBCode\Tags;

/**
* This class is the abstract base class for all BBCode tag classes.
*/
abstract class AbstractTag
{
/**
* The name of the tag type (lower cased).
* The sub class has to overwrite this constant.
*/
const NAME = '';

/**
* If true, inner tags will be treated as plain text
* The sub class has to overwrite this constant.
*/
const NO_PARSE = false;

/**
* This method renders a tag of this type.
* Has to return something, at least an empty string.
*
* @param string $html The generated HTML code so far - passed by reference
* @param bool $opening Is the tag opening (true) or closing (false)?
* @return void
*/
abstract public function render(&$html, $opening);

}

+ 0
- 169
app/Vendor/BBCode/Tokenizer/Token.php Zobrazit soubor

@@ -1,169 +0,0 @@
<?php

namespace App\Vendor\BBCode\Tokenizer;

/**
* The tokenizer splits a term into an array of tokens.
* Tokens are the parts of a text.
*/
class Token
{

/**
* Defines the type of a token.
* Example token value of a token with this type:
* '\n'
*
* @const int
*/
const TYPE_LINEBREAK = 0;

/**
* Defines the type of a token.
* Example token value of a token with this type:
* 'Hello world'
*
* @const int
*/
const TYPE_PLAIN_TEXT = 1;

/**
* Defines the type of a token.
* Example token value of a token with this type:
* '[b]'
*
* @const int
*/
const TYPE_TAG_OPENING = 2;

/**
* Defines the type of a token.
* Example token value of a token with this type:
* '[/b]'
*
* @const int
*/
const TYPE_TAG_CLOSING = 3;

/**
* The raw value of the token. Numbers are stored as string.
*
* @var string
*/
protected $value = null;

/**
* The type of the token. One of these constants:
* self::TYPE_WORD|self::TYPE_NUMBER|self::TYPE_CHARACTER
*
* @var int
*/
protected $type;

/**
* Position of the token in the input stream.
* It is stored as a debugging information.
*
* @var int
*/
protected $position;

/**
* The property value of the token (empty string = none)
*
* @var string
*/
protected $property;

/**
* Token constructor. The position must be >= 0.
*
* @param string $value The value of the token
* @param string $type The type of the token - one of these: self::TYPE_<NAME>
* @param int $position The position of the token in the original text
* @param string $property Optional: The property value of the token
*/
public function __construct($value, $type, $position, $property = '')
{
if (! is_string($value)) {
throw new \InvalidArgumentException(
'Error: Argument "value" has to be of type string but is of type "'.gettype($value).'"'
);
}
$this->value = $value;

if (! in_array($type, $this->getAllTypes())) {
throw new \InvalidArgumentException(
'Error: Argument "type" does not have the value of a known token type'
);
}
$this->type = $type;

if (! is_int($position)) {
throw new \InvalidArgumentException('Error: Argument "position" has to be of type int');
}
if ($position < 0) {
throw new \InvalidArgumentException('Error: Value of parameter "position" has to be >= zero');
}
$this->position = $position;

if (! is_string($property)) {
throw new \InvalidArgumentException(
'Error: Argument "property" has to be of type string but is of type "'.gettype($property).'"'
);
}
$this->property = $property;
}

/**
* Returns an array that contains the values of all
* possible types of token type constants.
*
* @see self::TYPE_<NAME>
*
* @return int[]
*/
public function getAllTypes()
{
return [self::TYPE_LINEBREAK, self::TYPE_PLAIN_TEXT, self::TYPE_TAG_OPENING, self::TYPE_TAG_CLOSING];
}

/**
* Getter for the value
*
* @return string
*/
public function getValue()
{
return $this->value;
}

/**
* Getter for the type
*
* @return string
*/
public function getType()
{
return $this->type;
}

/**
* Getter for the position
*
* @return int
*/
public function getPosition()
{
return $this->position;
}

/**
* @return string
*/
public function __toString()
{
return $this->value;
}

}

+ 0
- 149
app/Vendor/BBCode/Tokenizer/Tokenizer.php Zobrazit soubor

@@ -1,149 +0,0 @@
<?php

namespace App\Vendor\BBCode\Tokenizer;

use App\Vendor\BBCode\BBCode;
use App\Vendor\BBCode\Tag\AbstractTagType;

/**
* "Tokenization is the process of demarcating and possibly classifying
* sections of a string of input characters" (Source: Wikipedia)
* The tokenizer operates on the text and tries to split it into parts.
* The tokenizer is not very smart, it does not really care for grammar.
*/
class Tokenizer
{

/**
* Tokenize the text. Returns an array with the tokens.
* Note: There can be more than one subsequent plain text tokens
*
* @param string $text Render the passed BBCode string
* @param bool $escape Escape HTML entities? (Only "<" and ">"!)
* @param bool $keepLines Keep line breaks by replacing them with <br>?
* @return Token[]
*/
public function tokenize($text, $escape = true, $keepLines = true)
{
$tokens = [];
$length = mb_strlen($text);
$value = '';
$insideTag = false; // Means: The current position is between "[" and "]" (=a tag definition)
$insideName = false; // In a tag "[code]", "code" is the name of the tag
$insideString = false; // Properties of tags can be written as string with " at the start & end
$noParse = false; // If true, do not parse BBCode inside this tag
$tagName = ''; // Name of the current tag
$tagProperty = ''; // Property value of the current tag
$tagOpening = null; // True/false + null = undefined
$tagStartPos = 0;

// Loop over each character of the text
for ($pos = 0; $pos < $length; $pos++) {
$char = mb_substr($text, $pos, 1);

if ($keepLines) {
// Create line break token when \n
if ($char === "\n") {
$tokens[] = new Token($char, Token::TYPE_LINEBREAK, $pos);
}
// Ignore \r
if ($char === "\r") {
continue;
}
}

if (! $escape or ($char !== '<' and $char !== '>')) {
if ($insideTag) {
if ($char === '"') {
if ($insideString) {
$insideString = false;
} else {
$insideString = true;
}
} else {
// "]" closes a tag (if it is not used in a string)
if ($char == ']' and ! $insideString) {
if (! $noParse or (! $tagOpening and $this->checkNoParse($value))) {
$tokenType = $tagOpening ? Token::TYPE_TAG_OPENING : Token::TYPE_TAG_CLOSING;
$tokens[] = new Token($tagName, $tokenType, $tagStartPos, $tagProperty);
} else {
$tokens[] = new Token($value, Token::TYPE_PLAIN_TEXT, $tagStartPos);
}

$noParse = $this->checkNoParse($value);

$tagName = '';
$value = '';
$insideTag = false;
$insideName = false;
continue;
}

if ($insideName and ! $insideString) {
// This makes the current tag a closing tag
if ($char === '/') {
$tagOpening = false;
} else {
// This means a property starts
if ($char === '=') {
$insideName = false;
} elseif ($char === '[') { // Invalid tag - ignore it and start again
$value = '';
$tagName = '';
$tagOpening = true;
}
else {
$value .= mb_strtolower($char);
$tagName .= mb_strtolower($char);
}
}
} else { // If we are not inside the name we are inside a property
$tagProperty .= $char;
}
}
} else {
if ($char === '[') {
// Since a tag starts, plain text may end and we have to create a token for it
if ($value !== '') {
$tokens[] = new Token($value, Token::TYPE_PLAIN_TEXT, $tagStartPos);
$value = '';
}

$insideTag = true;
$insideName = true;
$tagOpening = true;
$tagStartPos = $pos;
$tagName = '';
} else {
// This is plain text
$value .= $char;
}
}
} else {
// Escape HTML chars "<" and ">"
$value .= htmlspecialchars($char);
}

}

// If the text ends with plain text we have to create the final plain text token now
if ($value !== '') {
$tokens[] = new Token($value, Token::TYPE_PLAIN_TEXT, $tagStartPos);
}

return $tokens;
}

/**
* Check if a tag is a tag that forbids parsing of its inner content
*
* @param string $tagName
* @return bool
*/
protected function checkNoParse($tagName)
{
// We do not want to throw any exceptions so we just return false
return false;
}

}

+ 8
- 1
composer.json Zobrazit soubor

@@ -4,10 +4,17 @@
"keywords": ["forum", "web1.0", "client"],
"license": "AGPL3",
"type": "project",
"repositories": [
{
"type": "vcs",
"url": "https://git.mos6581.com/Knockout/BBCode.git"
}
],
"require": {
"php": "^7.4",
"laravel/lumen-framework": "^8.0",
"nesbot/carbon": "^2.43"
"nesbot/carbon": "^2.43",
"knockout/bbcode": "dev-master"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.5",


+ 31
- 51
composer.lock Zobrazit soubor

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0ce9dd22cd325df894b40d30590f0cdb",
"content-hash": "383a2d2ab44182ee3aa0814ff7b823b9",
"packages": [
{
"name": "brick/math",
@@ -62,55 +62,6 @@
],
"time": "2020-08-18T23:57:15+00:00"
},
{
"name": "chriskonnertz/bbcode",
"version": "v1.1.2",
"source": {
"type": "git",
"url": "https://github.com/chriskonnertz/bbcode.git",
"reference": "d3acd447ee11265d4ef38b9058cef32adcafa245"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/chriskonnertz/bbcode/zipball/d3acd447ee11265d4ef38b9058cef32adcafa245",
"reference": "d3acd447ee11265d4ef38b9058cef32adcafa245",
"shasum": ""
},
"require": {
"php": ">=5.3.7"
},
"require-dev": {
"phpunit/phpunit": "~4"
},
"type": "library",
"autoload": {
"psr-0": {
"ChrisKonnertz\\BBCode": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kai Mallea",
"email": "kmallea@gmail.com"
},
{
"name": "Chris Konnertz"
}
],
"description": "A naive attempt at a BBCode 'parser' written in PHP. It uses regex and thus fails at complex, nested tags.",
"keywords": [
"bbcode"
],
"support": {
"issues": "https://github.com/chriskonnertz/bbcode/issues",
"source": "https://github.com/chriskonnertz/bbcode/tree/master"
},
"time": "2018-06-17T13:58:51+00:00"
},
{
"name": "doctrine/inflector",
"version": "2.0.3",
@@ -1910,6 +1861,33 @@
},
"time": "2020-11-02T14:01:41+00:00"
},
{
"name": "knockout/bbcode",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://git.mos6581.com/Knockout/BBCode.git",
"reference": "c06bf463f5c701c398852b413c1a8210c5c9c165"
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "5.6.*"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-0": {
"Knockout": "src/"
}
},
"license": [
"MIT"
],
"description": "php parser for bb code",
"time": "2021-01-01T23:15:08+00:00"
},
{
"name": "laravel/lumen-framework",
"version": "v8.2.1",
@@ -7391,7 +7369,9 @@
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"stability-flags": {
"knockout/bbcode": 20
},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {


+ 6
- 0
resources/views/partial/bbcode/quote.blade.php Zobrazit soubor

@@ -0,0 +1,6 @@
<div class="quote">
<a class="user" href="{{ route('thread', ['thread' => $thread, 'page' => $page]) }}#post-{{ $postId }}">{{ $username }}</a>
<div class="postContent">
{!! $content !!}
</div>
</div>

+ 1
- 1
resources/views/partial/post.blade.php Zobrazit soubor

@@ -6,7 +6,7 @@
<div class="userForeground">
<img class="avatar" src="{{ $post->user->avatar }}" height="32px" />
<a href="/user/{{ $post->user->id }}" class="username">{{ $post->user->username }}</a>
<a class="date" href="#post-{{ $post->id }}">9 months ago</a>
<a class="date" href="#post-{{ $post->id }}">{{ $post->dateDiff() }}</a>
</div>
</div>
<div class="row post">


Načítá se…
Zrušit
Uložit