#652 Support BB Code at feed news display

This commit is contained in:
Ulrich Block 2015-11-02 22:34:35 +01:00
parent 0e91e50d80
commit 78d0bb8dba
48 changed files with 4850 additions and 1 deletions

View File

@ -84,11 +84,16 @@ http://morrisjs.github.io/morris.js/
Licensed under the BSD-2-Clause License
http://opensource.org/licenses/BSD-2-Clause
* Rapha<EFBFBD>
* Raphael
http://raphaeljs.com
Released under the MIT license
http://opensource.org/licenses/MIT
* Decoda
https://github.com/milesj/decoda
Released under the MIT license
http://opensource.org/licenses/MIT
Shipped with Easy-WI but modified and fitted to Easy-WI:

View File

@ -41,6 +41,9 @@ if ((!isset($admin_id) or $main != 1) or (isset($admin_id) and !isanyadmin($admi
die('No Access');
}
include(EASYWIDIR . '/third_party/Decoda/autoloader.php');
use Decoda\Decoda;
$sprache_bad = getlanguagefile('home', $user_language, $reseller_id);
$statsArray = array(
@ -251,6 +254,19 @@ if ($ui->smallletters('w', 2, 'get') == 'da' or (!$ui->smallletters('w', 2, 'get
}
}
if (preg_match('/(\[\/img\]|\[\/url\]|\[\/b\]|\[\/h1\])/i', $text)) {
$code = new \Decoda\Decoda($text);
$code->addFilter(new \Decoda\Filter\DefaultFilter());
$code->addFilter(new \Decoda\Filter\ImageFilter());
$code->addFilter(new \Decoda\Filter\BlockFilter());
$code->addFilter(new \Decoda\Filter\EmailFilter());
$code->addFilter(new \Decoda\Filter\UrlFilter());
$code->addFilter(new \Decoda\Filter\VideoFilter());
$code->addFilter(new \Decoda\Filter\HeadLineFilter());
$code->addHook(new \Decoda\Hook\ClickableHook());
$text = $code->parse();
}
$title = $row2['newsTitle'];
if (strlen($row2['newsTitle']) <= 1) {

View File

@ -40,6 +40,10 @@ if ((!isset($user_id) or !$main == "1") or (isset($user_id) and !isanyuser($user
header('Location: login.php');
die('No Access');
}
include(EASYWIDIR . '/third_party/Decoda/autoloader.php');
use Decoda\Decoda;
$sprache_bad = getlanguagefile('home', $user_language, $reseller_id);
if (isset($admin_id) and $reseller_id != 0 and $admin_id != $reseller_id) {
@ -198,6 +202,19 @@ if ($ui->smallletters('w', 2, 'get') == 'da' or (!$ui->smallletters('w', 2, 'get
}
}
if (preg_match('/(\[\/img\]|\[\/url\]|\[\/b\]|\[\/h1\])/i', $text)) {
$code = new \Decoda\Decoda($text);
$code->addFilter(new \Decoda\Filter\DefaultFilter());
$code->addFilter(new \Decoda\Filter\ImageFilter());
$code->addFilter(new \Decoda\Filter\BlockFilter());
$code->addFilter(new \Decoda\Filter\EmailFilter());
$code->addFilter(new \Decoda\Filter\UrlFilter());
$code->addFilter(new \Decoda\Filter\VideoFilter());
$code->addFilter(new \Decoda\Filter\HeadLineFilter());
$code->addHook(new \Decoda\Hook\ClickableHook());
$text = $code->parse();
}
$title = $row2['newsTitle'];
if (strlen($row2['newsTitle']) <= 1) {

View File

@ -0,0 +1,77 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda;
/**
* Defines the methods for all Components to implement.
*/
interface Component {
/**
* Add a loader.
*
* @param \Decoda\Loader $loader
* @return \Decoda\Component
*/
public function addLoader(Loader $loader);
/**
* Method called immediately after the constructor.
*
* @return void
*/
public function construct();
/**
* Return a specific configuration key value.
*
* @param string $key
* @return mixed
*/
public function getConfig($key);
/**
* Return all the Loaders.
*
* @return \Decoda\Loader[]
*/
public function getLoaders();
/**
* Return the Decoda parser.
*
* @return \Decoda\Decoda
*/
public function getParser();
/**
* Return a message string from the parser.
*
* @param string $key
* @param array $vars
* @return string
*/
public function message($key, array $vars = array());
/**
* Modify configuration.
*
* @param array $config
* @return \Decoda\Component
*/
public function setConfig(array $config);
/**
* Set the Decoda parser.
*
* @param \Decoda\Decoda $parser
* @return \Decoda\Component
*/
public function setParser(Decoda $parser);
}

View File

@ -0,0 +1,112 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Component;
use Decoda\Decoda;
use Decoda\Component;
use Decoda\Loader;
/**
* Provides default shared functionality for Filters, Hooks and Engines.
*/
abstract class AbstractComponent implements Component {
/**
* Configuration.
*
* @type array
*/
protected $_config = array();
/**
* List of Loaders.
*
* @type \Decoda\Loader[]
*/
protected $_loaders = array();
/**
* Decoda object.
*
* @type \Decoda\Decoda
*/
protected $_parser;
/**
* Apply configuration.
*
* @param array $config
*/
public function __construct(array $config = array()) {
$this->setConfig($config);
$this->construct();
}
/**
* {@inheritdoc}
*/
public function addLoader(Loader $loader) {
$this->_loaders[] = $loader;
return $this;
}
/**
* {@inheritdoc}
*/
public function construct() {
return;
}
/**
* {@inheritdoc}
*/
public function getConfig($key) {
return isset($this->_config[$key]) ? $this->_config[$key] : null;
}
/**
* {@inheritdoc}
*/
public function getLoaders() {
return $this->_loaders;
}
/**
* {@inheritdoc}
*/
public function getParser() {
return $this->_parser;
}
/**
* {@inheritdoc}
*/
public function message($key, array $vars = array()) {
return $this->getParser()->message($key, $vars);
}
/**
* {@inheritdoc}
*/
public function setConfig(array $config) {
$this->_config = $config + $this->_config;
return $this;
}
/**
* {@inheritdoc}
*/
public function setParser(Decoda $parser) {
$this->_parser = $parser;
return $this;
}
}

1668
web/third_party/Decoda/Decoda/Decoda.php vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda;
/**
* This interface represents the rendering engine for tags that use a template.
* It contains the path were the templates are located and the logic to render these templates.
*/
interface Engine extends Component {
/**
* Add a template lookup path.
*
* @param string $path
* @return \Decoda\Engine
*/
public function addPath($path);
/**
* Return the current filter.
*
* @return \Decoda\Filter
*/
public function getFilter();
/**
* Returns the paths to the templates.
*
* @return string
*/
public function getPaths();
/**
* Renders the tag by using the defined templates.
*
* @param array $tag
* @param string $content
* @return string
*/
public function render(array $tag, $content);
/**
* Sets the current used filter.
*
* @param \Decoda\Filter $filter
* @return \Decoda\Engine
*/
public function setFilter(Filter $filter);
}

View File

@ -0,0 +1,79 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Engine;
use Decoda\Component\AbstractComponent;
use Decoda\Filter;
use Decoda\Engine;
/**
* Provides default methods for engines.
*/
abstract class AbstractEngine extends AbstractComponent implements Engine {
/**
* Lookup paths.
*
* @type array
*/
protected $_paths = array();
/**
* Current filter.
*
* @type \Decoda\Filter
*/
protected $_filter;
/**
* {@inheritdoc}
*/
public function addPath($path) {
if (substr($path, -1) !== '/') {
$path .= '/';
}
$this->_paths[] = $path;
return $this;
}
/**
* Escape HTML characters and entities.
*
* @param string $string
* @return string
*/
public function escape($string) {
return $this->getParser()->escape($string);
}
/**
* {@inheritdoc}
*/
public function getFilter() {
return $this->_filter;
}
/**
* {@inheritdoc}
*/
public function getPaths() {
return $this->_paths;
}
/**
* {@inheritdoc}
*/
public function setFilter(Filter $filter) {
$this->_filter = $filter;
return $this;
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Engine;
use Decoda\Exception\IoException;
/**
* Renders tags by using PHP as template engine.
*/
class PhpEngine extends AbstractEngine {
/**
* {@inheritdoc}
*
* @throws \Decoda\Exception\IoException
*/
public function render(array $tag, $content) {
$setup = $this->getFilter()->getTag($tag['tag']);
$attributes = $tag['attributes'];
// Dashes aren't allowed in variables, so change to underscores
foreach ($attributes as $key => $value) {
$attributes[str_replace('-', '_', $key)] = $value;
}
foreach ($this->getPaths() as $path) {
$template = sprintf('%s%s.php', $path, $setup['template']);
if (file_exists($template)) {
extract($attributes, EXTR_OVERWRITE);
ob_start();
include $template;
return trim(ob_get_clean());
}
}
throw new IoException(sprintf('Template file %s does not exist', $setup['template']));
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Exception;
/**
* Exception used when a file read or write fails.
*/
class IoException extends \RuntimeException {
}

View File

@ -0,0 +1,15 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Exception;
/**
* Exception used an undefined filter is accessed.
*/
class MissingFilterException extends \OutOfRangeException {
}

View File

@ -0,0 +1,15 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Exception;
/**
* Exception used an undefined hook is accessed.
*/
class MissingHookException extends \OutOfRangeException {
}

View File

@ -0,0 +1,15 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Exception;
/**
* Exception used an undefined locale is accessed.
*/
class MissingLocaleException extends \OutOfRangeException {
}

View File

@ -0,0 +1,15 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Exception;
/**
* Exception used when an unsupported type or value occurs.
*/
class UnsupportedTypeException extends \UnexpectedValueException {
}

View File

@ -0,0 +1,64 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda;
/**
* Defines the methods for all Filters to implement.
*/
interface Filter extends Component {
/**
* Regex patterns for attribute parsing.
*/
const WILDCARD = '/(.*?)/';
const ALPHA = '/^[a-z_\-\s]+$/i';
const ALNUM = '/^[a-z0-9,_\s\.\-\+\/]+$/i';
const NUMERIC = '/^[0-9,\.\-\+\/]+$/';
/**
* Return a tag if it exists, and merge with defaults.
*
* @param string $tag
* @return array
*/
public function getTag($tag);
/**
* Return all tags.
*
* @return array
*/
public function getTags();
/**
* Parse the node and its content into an HTML tag.
*
* @param array $tag
* @param string $content
* @return string
*/
public function parse(array $tag, $content);
/**
* Add any hook dependencies.
*
* @param \Decoda\Decoda $decoda
* @return \Decoda\Filter
*/
public function setupHooks(Decoda $decoda);
/**
* Strip a node and remove content dependent on settings.
*
* @param array $tag
* @param string $content
* @return string
*/
public function strip(array $tag, $content);
}

View File

@ -0,0 +1,281 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
use Decoda\Component\AbstractComponent;
use Decoda\Exception\MissingFilterException;
use Decoda\Filter;
/**
* A filter defines the list of tags and its associative markup to parse out of a string.
* Supports a wide range of parameters to customize the output of each tag.
*/
abstract class AbstractFilter extends AbstractComponent implements Filter {
/**
* Default tag configuration.
*
* @type array
*/
protected $_defaults = array(
/**
* tag - (string) Decoda tag
* htmlTag - (string) HTML replacement tag
* template - (string) Template file to use for rendering
* displayType - (constant) Type of HTML element: block or inline
* allowedTypes - (constant) What types of elements are allowed to be nested
* aliasFor - (string) Inherits settings from another filter
*/
'tag' => '',
'htmlTag' => '',
'template' => '',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'aliasFor' => '',
/**
* attributes - (array) Custom attributes to parse out of the Decoda tag
* mapAttributes - (array) Map parsed and custom attributes to HTML equivalent attribute names
* htmlAttributes - (array) Custom HTML attributes to append to the parsed tag
* aliasAttributes - (array) Custom attributes to alias to another attribute
* escapeAttributes - (boolean) Escape HTML entities within the parsed attributes
*/
'attributes' => array(),
'mapAttributes' => array(),
'htmlAttributes' => array(),
'aliasAttributes' => array(),
'escapeAttributes' => true,
/**
* lineBreaks - (boolean) Convert line breaks within the content body
* autoClose - (boolean) HTML tag is self closing
* preserveTags - (boolean) Will not convert nested Decoda markup within this tag
* onlyTags - (boolean) Only Decoda tags are allowed within this tag, no text nodes
*/
'lineBreaks' => Decoda::NL_CONVERT,
'autoClose' => false,
'preserveTags' => false,
'onlyTags' => false,
/**
* contentPattern - (string) Regex pattern that the content or default attribute must pass
* stripContent - (boolean) Should content within tags be removed when stripping tags
*/
'contentPattern' => '',
'stripContent' => false,
/**
* parent - (array) List of Decoda tags that this tag can only be a direct child of
* childrenWhitelist - (array) List of Decoda tags that can only be a direct descendant
* childrenBlacklist - (array) List of Decoda tags that can not be a direct descendant
* maxChildDepth - (integer) Max depth for nested children of the same tag (-1 to disable)
* persistContent - (boolean) Should we persist text content from within deeply nested tags (but remove their wrapping tags)
*/
'parent' => array(),
'childrenWhitelist' => array(),
'childrenBlacklist' => array(),
'maxChildDepth' => -1,
'persistContent' => true
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array();
/**
* Generate all the tags on construction.
*/
public function construct() {
$tags = array();
$defaults = $this->_defaults;
foreach ($this->_tags as $tag => $settings) {
$filter = $settings;
$filter['tag'] = $tag;
// Inherit from another tag and merge recursively
if (!empty($filter['aliasFor'])) {
$base = $tags[$filter['aliasFor']];
foreach ($filter as $key => $value) {
if (is_array($value)) {
$base[$key] = $value + $base[$key];
} else if ($value !== '') {
$base[$key] = $value;
}
}
$filter = $base;
// Or inherit from defaults
} else {
$filter = array_merge($defaults, $filter);
}
// Alias attributes
if ($filter['aliasAttributes']) {
foreach ($filter['aliasAttributes'] as $attr => $alias) {
$filter['attributes'][$attr] = $filter['attributes'][$alias];
}
}
$tags[$tag] = $filter;
}
$this->_tags = $tags;
}
/**
* {@inheritdoc}
*
* @throws \Decoda\Exception\MissingFilterException
*/
public function getTag($tag) {
if (isset($this->_tags[$tag])) {
return $this->_tags[$tag];
}
throw new MissingFilterException(sprintf('No filter can be found with %s tag', $tag));
}
/**
* {@inheritdoc}
*/
public function getTags() {
return $this->_tags;
}
/**
* {@inheritdoc}
*/
public function parse(array $tag, $content) {
$setup = $this->getTag($tag['tag']);
$parser = $this->getParser();
$xhtml = $parser->getConfig('xhtmlOutput');
$content = !empty($tag['content']) ? $tag['content'] : $content;
// Test for an empty filter or empty tag
if (!$setup || (!$content && $parser->getConfig('removeEmpty'))) {
return null;
}
// Merge arguments with method of same tag name
// If the method returns false, exit early
if (method_exists($this, $tag['tag'])) {
if ($response = call_user_func_array(array($this, $tag['tag']), array($tag, $content))) {
list($tag, $content) = $response;
} else {
return null;
}
}
if ($content) {
// If content doesn't match the pattern, don't wrap in a tag
if ($setup['contentPattern']) {
if (!preg_match($setup['contentPattern'], $content)) {
return '';
}
}
// Process line breaks
switch ($setup['lineBreaks']) {
case Decoda::NL_CONVERT:
$content = str_replace("\r", "", $parser->convertLineBreaks($content));
break;
case Decoda::NL_REMOVE:
$content = str_replace(array("\r", "\n"), "", $content);
break;
}
}
// Format attributes
$attributes = (array) $setup['htmlAttributes'];
$attr = '';
if ($tag['attributes']) {
foreach ($tag['attributes'] as $key => $value) {
if ($key === 'default' || mb_substr($value, 0, 11) === 'javascript:') {
continue;
}
if ($setup['escapeAttributes']) {
$value = $parser->escape($value);
}
if (!empty($attributes[$key])) {
$attributes[$key] .= ' ' . $value;
} else {
$attributes[$key] = $value;
}
}
}
foreach ($attributes as $key => $value) {
$attr .= ' ' . $key . '="' . $value . '"';
}
// Use a template if it exists
if ($setup['template']) {
$tag['attributes'] = $attributes + $this->_config;
$engine = $parser->getEngine();
$engine->setFilter($this);
$parsed = $engine->render($tag, $content);
if ($setup['lineBreaks'] !== Decoda::NL_PRESERVE) {
$parsed = str_replace(array("\r", "\n"), "", $parsed);
// Normalize
} else {
$parsed = $parser->convertNewlines($parsed);
}
return $parsed;
}
// Build HTML tag
$html = $setup['htmlTag'];
if (is_array($html)) {
$html = $html[$xhtml];
}
if ($setup['autoClose']) {
$parsed = '<' . $html . $attr . ($xhtml ? ' /' : '') . '>';
} else {
$parsed = '<' . $html . $attr . '>' . $content . '</' . $html . '>';
}
return $parsed;
}
/**
* {@inheritdoc}
*/
public function setupHooks(Decoda $decoda) {
return $this;
}
/**
* {@inheritdoc}
*/
public function strip(array $tag, $content) {
$setup = $this->getTag($tag['tag']);
if (!$setup || $setup['stripContent']) {
return '';
}
return $content;
}
}

View File

@ -0,0 +1,134 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for block styled elements.
*/
class BlockFilter extends AbstractFilter {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'spoilerToggle' => "$('#spoiler-content-{id}').toggle();"
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'align' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'attributes' => array(
'default' => array('/^(?:left|center|right|justify)$/i', 'align-{default}')
),
'mapAttributes' => array(
'default' => 'class'
)
),
'left' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'class' => 'align-left'
)
),
'right' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'class' => 'align-right'
)
),
'center' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'class' => 'align-center'
)
),
'justify' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'class' => 'align-justify'
)
),
'float' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'attributes' => array(
'default' => array('/^(?:left|right|none)$/i', 'float-{default}')
),
'mapAttributes' => array(
'default' => 'class'
)
),
'hide' => array(
'htmlTag' => 'span',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'style' => 'display: none'
),
'stripContent' => true
),
'alert' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'class' => 'decoda-alert'
),
'stripContent' => true
),
'note' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'htmlAttributes' => array(
'class' => 'decoda-note'
),
'stripContent' => true
),
'div' => array(
'htmlTag' => 'div',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'attributes' => array(
'default' => self::ALPHA,
'class' => self::ALNUM
),
'mapAttributes' => array(
'default' => 'id'
),
'stripContent' => true
),
'spoiler' => array(
'template' => 'spoiler',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'stripContent' => true
)
);
}

View File

@ -0,0 +1,73 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
use Decoda\Hook\CodeHook;
/**
* Provides tags for code block and variable elements.
*/
class CodeFilter extends AbstractFilter {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'classPrefix' => 'lang-',
'highlightAttribute' => 'data-line'
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'code' => array(
'template' => 'code',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'lineBreaks' => Decoda::NL_PRESERVE,
'preserveTags' => true,
'attributes' => array(
'default' => self::ALPHA,
'hl' => self::NUMERIC
),
'mapAttributes' => array(
'default' => 'lang'
),
'stripContent' => true
),
'source' => array(
'htmlTag' => 'code',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
'var' => array(
'htmlTag' => 'var',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
)
);
/**
* Add any hook dependencies.
*
* @param \Decoda\Decoda $decoda
* @return \Decoda\Filter\CodeFilter
*/
public function setupHooks(Decoda $decoda) {
$decoda->addHook(new CodeHook());
return $this;
}
}

View File

@ -0,0 +1,110 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
use \DateTime;
/**
* Provides tags for basic font styling.
*/
class DefaultFilter extends AbstractFilter {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'timeFormat' => 'D, M jS Y, H:i'
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'b' => array(
'htmlTag' => array('b', 'strong'),
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
'i' => array(
'htmlTag' => array('i', 'em'),
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
'u' => array(
'htmlTag' => 'u',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
's' => array(
'htmlTag' => 'del',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
'sub' => array(
'htmlTag' => 'sub',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
'sup' => array(
'htmlTag' => 'sup',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE
),
'abbr' => array(
'htmlTag' => 'abbr',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE,
'attributes' => array(
'default' => AbstractFilter::ALNUM
),
'mapAttributes' => array(
'default' => 'title'
)
),
'br' => array(
'htmlTag' => 'br',
'autoClose' => true,
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_NONE
),
'hr' => array(
'htmlTag' => 'hr',
'autoClose' => true,
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE
),
'time' => array(
'htmlTag' => 'time',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_NONE
)
);
/**
* Parse the timestamps for the time tag.
*
* @param array $tag
* @param string $content
* @return array
*/
public function time(array $tag, $content) {
$timestamp = is_numeric($content) ? $content : strtotime($content);
$content = date($this->getConfig('timeFormat'), $timestamp);
$tag['attributes']['datetime'] = date(DateTime::ISO8601, $timestamp);
return array($tag, $content);
}
}

View File

@ -0,0 +1,109 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for emails. Will obfuscate emails against bots.
*/
class EmailFilter extends AbstractFilter {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'encrypt' => true
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'email' => array(
'htmlTag' => 'a',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_NONE,
'escapeAttributes' => false,
'attributes' => array(
'default' => true
)
),
'mail' => array(
'aliasFor' => 'email'
)
);
/**
* Encrypt the email before parsing it within tags.
*
* @param array $tag
* @param string $content
* @return string
*/
public function parse(array $tag, $content) {
if (empty($tag['attributes']['default'])) {
$email = $content;
$default = false;
} else {
$email = $tag['attributes']['default'];
$default = true;
}
// Return an invalid email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return $content;
}
$encrypted = '';
if ($this->getConfig('encrypt')) {
$length = mb_strlen($email);
if ($length > 0) {
for ($i = 0; $i < $length; ++$i) {
$encrypted .= '&#' . ord(mb_substr($email, $i, 1)) . ';';
}
}
} else {
$encrypted = $email;
}
$tag['attributes']['href'] = 'mailto:' . $encrypted;
if ($this->getParser()->getConfig('shorthandLinks')) {
$tag['content'] = $this->message('mail');
return '[' . parent::parse($tag, $content) . ']';
}
if (!$default) {
$tag['content'] = $encrypted;
}
return parent::parse($tag, $content);
}
/**
* Strip a node but keep the email regardless of location.
*
* @param array $tag
* @param string $content
* @return string
*/
public function strip(array $tag, $content) {
$email = isset($tag['attributes']['default']) ? $tag['attributes']['default'] : $content;
return parent::strip($tag, $email);
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
/**
* An empty filter for no operation events.
*/
class EmptyFilter extends AbstractFilter {
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'root' => array()
);
}

View File

@ -0,0 +1,21 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
use Decoda\Filter\AbstractFilter;
class HeadLineFilter extends AbstractFilter {
protected $_tags = array(
'h1' => array(
'htmlTag' => 'h3',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE
)
);
}

View File

@ -0,0 +1,78 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for images.
*/
class ImageFilter extends AbstractFilter {
/**
* Regex pattern.
*/
const IMAGE_PATTERN = '/^((?:https?:\/)?(?:\.){0,2}\/)((?:.*?)\.(jpg|jpeg|png|gif|bmp))(\?[^#]+)?(#[\-\w]+)?$/is';
const WIDTH_HEIGHT = '/^([0-9%]{1,4}+)x([0-9%]{1,4}+)$/';
const DIMENSION = '/^[0-9%]{1,4}+$/';
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'img' => array(
'htmlTag' => 'img',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::IMAGE_PATTERN,
'autoClose' => true,
'attributes' => array(
'default' => self::WIDTH_HEIGHT,
'width' => self::DIMENSION,
'height' => self::DIMENSION,
'alt' => self::WILDCARD
)
),
'image' => array(
'aliasFor' => 'img'
)
);
/**
* Use the content as the image source.
*
* @param array $tag
* @param string $content
* @return string
*/
public function parse(array $tag, $content) {
// If more than 1 http:// is found in the string, possible XSS attack
if ((mb_substr_count($content, 'http://') + mb_substr_count($content, 'https://')) > 1) {
return null;
}
$tag['attributes']['src'] = $content;
if (!empty($tag['attributes']['default'])) {
list($width, $height) = explode('x', $tag['attributes']['default']);
$tag['attributes']['width'] = $width;
$tag['attributes']['height'] = $height;
}
if (empty($tag['attributes']['alt'])) {
$tag['attributes']['alt'] = '';
}
return parent::parse($tag, $content);
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for ordered and unordered lists.
*/
class ListFilter extends AbstractFilter {
const LIST_TYPE = '/^[-a-z]+$/i';
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'olist' => array(
'htmlTag' => 'ol',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'lineBreaks' => Decoda::NL_REMOVE,
'childrenWhitelist' => array('li', '*'),
'onlyTags' => true,
'attributes' => array(
'default' => array(self::LIST_TYPE, 'type-{default}')
),
'mapAttributes' => array(
'default' => 'class'
),
'htmlAttributes' => array(
'class' => 'decoda-olist'
)
),
'ol' => array(
'aliasFor' => 'olist'
),
'list' => array(
'htmlTag' => 'ul',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'lineBreaks' => Decoda::NL_REMOVE,
'childrenWhitelist' => array('li', '*'),
'onlyTags' => true,
'attributes' => array(
'default' => array(self::LIST_TYPE, 'type-{default}')
),
'mapAttributes' => array(
'default' => 'class'
),
'htmlAttributes' => array(
'class' => 'decoda-list'
)
),
'ul' => array(
'aliasFor' => 'list'
),
'li' => array(
'htmlTag' => 'li',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'parent' => array('olist', 'list', 'ol', 'ul')
),
'*' => array(
'htmlTag' => 'li',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'childrenBlacklist' => array('olist', 'list', 'ol', 'ul', 'li'),
'parent' => array('olist', 'list', 'ol', 'ul')
)
);
}

View File

@ -0,0 +1,49 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides the tag for quoting users and blocks of texts.
*/
class QuoteFilter extends AbstractFilter {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'dateFormat' => 'M jS Y, H:i:s'
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'quote' => array(
'template' => 'quote',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'attributes' => array(
'default' => self::WILDCARD,
'date' => self::WILDCARD
),
'mapAttributes' => array(
'default' => 'author'
),
'maxChildDepth' => 2,
'persistContent' => false,
'stripContent' => true
)
);
}

View File

@ -0,0 +1,121 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for tables, rows and cells.
*/
class TableFilter extends AbstractFilter {
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'table' => array(
'htmlTag' => 'table',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BLOCK,
'lineBreaks' => Decoda::NL_REMOVE,
'onlyTags' => true,
'childrenWhitelist' => array('tr', 'row', 'thead', 'tbody', 'tfoot'),
'attributes' => array(
'class' => self::ALNUM
),
'htmlAttributes' => array(
'class' => 'decoda-table'
)
),
'thead' => array(
'htmlTag' => 'thead',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BLOCK,
'lineBreaks' => Decoda::NL_REMOVE,
'onlyTags' => true,
'childrenWhitelist' => array('tr', 'row'),
'parent' => array('table')
),
'tbody' => array(
'htmlTag' => 'tbody',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BLOCK,
'lineBreaks' => Decoda::NL_REMOVE,
'onlyTags' => true,
'childrenWhitelist' => array('tr', 'row'),
'parent' => array('table')
),
'tfoot' => array(
'htmlTag' => 'tfoot',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BLOCK,
'lineBreaks' => Decoda::NL_REMOVE,
'onlyTags' => true,
'childrenWhitelist' => array('tr', 'row'),
'parent' => array('table')
),
'tr' => array(
'htmlTag' => 'tr',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BLOCK,
'lineBreaks' => Decoda::NL_REMOVE,
'onlyTags' => true,
'childrenWhitelist' => array('td', 'th', 'col'),
'parent' => array('table', 'thead', 'tbody', 'tfoot')
),
'row' => array(
'aliasFor' => 'tr'
),
'td' => array(
'htmlTag' => 'td',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'parent' => array('tr', 'row'),
'attributes' => array(
'default' => self::NUMERIC,
'cols' => self::NUMERIC,
'rows' => self::NUMERIC
),
'aliasAttributes' => array(
'colspan' => 'cols',
'rowspan' => 'rows'
),
'mapAttributes' => array(
'default' => 'colspan',
'cols' => 'colspan',
'rows' => 'rowspan'
)
),
'col' => array(
'aliasFor' => 'td'
),
'th' => array(
'htmlTag' => 'th',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_BOTH,
'parent' => array('tr', 'row'),
'attributes' => array(
'default' => self::NUMERIC,
'cols' => self::NUMERIC,
'rows' => self::NUMERIC
),
'aliasAttributes' => array(
'colspan' => 'cols',
'rowspan' => 'rows'
),
'mapAttributes' => array(
'default' => 'colspan',
'cols' => 'colspan',
'rows' => 'rowspan'
)
)
);
}

View File

@ -0,0 +1,89 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for text and font styling.
*/
class TextFilter extends AbstractFilter {
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'font' => array(
'htmlTag' => 'span',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE,
'escapeAttributes' => false,
'attributes' => array(
'default' => array('/^[a-z0-9\-\s,\.\']+$/i', 'font-family: {default}')
),
'mapAttributes' => array(
'default' => 'style'
)
),
'size' => array(
'htmlTag' => 'span',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE,
'attributes' => array(
'default' => array('/^[1-2]{1}[0-9]{1}$/', 'font-size: {default}px'),
),
'mapAttributes' => array(
'default' => 'style'
)
),
'color' => array(
'htmlTag' => 'span',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE,
'attributes' => array(
'default' => array('/^(?:#[0-9a-f]{3,6}|[a-z]+)$/i', 'color: {default}'),
),
'mapAttributes' => array(
'default' => 'style'
)
),
'h1' => array(
'htmlTag' => 'h1',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_INLINE
),
'h2' => array(
'htmlTag' => 'h2',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_INLINE
),
'h3' => array(
'htmlTag' => 'h3',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_INLINE
),
'h4' => array(
'htmlTag' => 'h4',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_INLINE
),
'h5' => array(
'htmlTag' => 'h5',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_INLINE
),
'h6' => array(
'htmlTag' => 'h6',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_INLINE
)
);
}

View File

@ -0,0 +1,107 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides tags for URLs.
*/
class UrlFilter extends AbstractFilter {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'protocols' => array('http', 'https', 'ftp', 'irc', 'telnet'),
'defaultProtocol' => 'http'
);
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'url' => array(
'htmlTag' => 'a',
'displayType' => Decoda::TYPE_INLINE,
'allowedTypes' => Decoda::TYPE_INLINE,
'attributes' => array(
'default' => true
),
'mapAttributes' => array(
'default' => 'href'
)
),
'link' => array(
'aliasFor' => 'url'
)
);
/**
* Using shorthand variation if enabled.
*
* @param array $tag
* @param string $content
* @return string
*/
public function parse(array $tag, $content) {
$url = isset($tag['attributes']['href']) ? $tag['attributes']['href'] : $content;
$protocols = $this->getConfig('protocols');
$defaultProtocol = $this->getConfig('defaultProtocol');
$hasProtocol = preg_match('/^(' . implode('|', $protocols) . ')/i', $url);
if (!in_array($defaultProtocol, $protocols)) {
$defaultProtocol = 'http';
}
// Allow relative and absolute paths, else check protocols
if (!preg_match('/^(\.\.?)?\//', $url)) {
if (!$hasProtocol) {
// Only allow if no protocol exists, just not the ones not in the list
if (preg_match('/^(?![a-z]+:\/\/)/', $url) && filter_var($defaultProtocol . '://' . $url, FILTER_VALIDATE_URL)) {
$url = $defaultProtocol . '://' . $url;
} else {
return $url;
}
}
// Return an invalid URL
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return $url;
}
}
$tag['attributes']['href'] = $url;
if ($this->getParser()->getConfig('shorthandLinks')) {
$tag['content'] = $this->message('link');
return '[' . parent::parse($tag, $content) . ']';
}
return parent::parse($tag, $content);
}
/**
* Strip a node but keep the URL regardless of location.
*
* @param array $tag
* @param string $content
* @return string
*/
public function strip(array $tag, $content) {
$url = isset($tag['attributes']['href']) ? $tag['attributes']['href'] : $content;
return parent::strip($tag, $url);
}
}

View File

@ -0,0 +1,235 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Filter;
use Decoda\Decoda;
/**
* Provides the tag for videos. Only a few video services are supported.
*/
class VideoFilter extends AbstractFilter {
/**
* Regex pattern.
*/
const VIDEO_PATTERN = '/^[-_a-z0-9]+$/is';
const SIZE_PATTERN = '/^(?:small|medium|large)$/i';
/**
* Supported tags.
*
* @type array
*/
protected $_tags = array(
'video' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'default' => self::ALPHA,
'size' => self::SIZE_PATTERN
)
),
'youtube' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'vimeo' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'veoh' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'vevo' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
//'size' => self::SIZE_PATTERN Vevo has no sizes
)
),
'liveleak' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'dailymotion' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'myspace' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'collegehumor' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'funnyordie' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
'wegame' => array(
'template' => 'video',
'displayType' => Decoda::TYPE_BLOCK,
'allowedTypes' => Decoda::TYPE_NONE,
'contentPattern' => self::VIDEO_PATTERN,
'attributes' => array(
'size' => self::SIZE_PATTERN
)
),
);
/**
* Video formats.
*
* @type array
*/
protected $_formats = array(
'youtube' => array(
'small' => array(560, 315),
'medium' => array(640, 360),
'large' => array(853, 480),
'player' => 'iframe',
'path' => '//youtube.com/embed/{id}'
),
'vimeo' => array(
'small' => array(400, 225),
'medium' => array(550, 309),
'large' => array(700, 394),
'player' => 'iframe',
'path' => '//player.vimeo.com/video/{id}'
),
'vevo' => array(
'small' => array(400, 225),
'medium' => array(575, 324),
'large' => array(955, 538),
'player' => 'embed',
'path' => '//videoplayer.vevo.com/embed/Embedded?videoId={id}&playlist=false&autoplay=0&playerId=62FF0A5C-0D9E-4AC1-AF04-1D9E97EE3961&playerType=embedded'
),
'veoh' => array(
'small' => array(410, 341),
'medium' => array(610, 507),
'large' => array(810, 674),
'player' => 'embed',
'path' => '//veoh.com/swf/webplayer/WebPlayer.swf?version=AFrontend.5.7.0.1390&permalinkId={id}&player=videodetailsembedded&videoAutoPlay=0&id=anonymous'
),
'liveleak' => array(
'small' => array(560, 315),
'medium' => array(640, 360),
'large' => array(853, 480),
'player' => 'iframe',
'path' => '//liveleak.com/e/{id}'
),
'dailymotion' => array(
'small' => array(320, 180),
'medium' => array(480, 270),
'large' => array(560, 315),
'player' => 'iframe',
'path' => '//dailymotion.com/embed/video/{id}'
),
'myspace' => array(
'small' => array(325, 260),
'medium' => array(425, 340),
'large' => array(525, 420),
'player' => 'embed',
'path' => '//mediaservices.myspace.com/services/media/embed.aspx/m={id},t=1,mt=video'
),
'collegehumor' => array(
'small' => array(300, 169),
'medium' => array(450, 254),
'large' => array(600, 338),
'player' => 'iframe',
'path' => '//collegehumor.com/e/{id}'
),
'funnyordie' => array(
'small' => array(512, 328),
'medium' => array(640, 400),
'large' => array(960, 580),
'player' => 'iframe',
'path' => '//funnyordie.com/embed/{id}'
),
'wegame' => array(
'small' => array(325, 223),
'medium' => array(480, 330),
'large' => array(640, 440),
'player' => 'embed',
'path' => '//wegame.com/static/flash/player.swf?xmlrequest=http://www.wegame.com/player/video/{id}&embedPlayer=true'
),
);
/**
* 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');
if (empty($this->_formats[$provider])) {
return sprintf('(Invalid %s video code)', $provider);
}
$video = $this->_formats[$provider];
$size = isset($video[$size]) ? $video[$size] : $video['medium'];
$tag['attributes']['width'] = $size[0];
$tag['attributes']['height'] = $size[1];
$tag['attributes']['player'] = $video['player'];
$tag['attributes']['url'] = str_replace(array('{id}', '{width}', '{height}'), array($content, $size[0], $size[1]), $video['path']);
return parent::parse($tag, $content);
}
}

78
web/third_party/Decoda/Decoda/Hook.php vendored Normal file
View File

@ -0,0 +1,78 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda;
/**
* Defines the methods for all Hooks to implement.
*/
interface Hook extends Component {
/**
* Process the node's inner content after the filters have finished.
*
* @param string $content
* @return string
*/
public function afterContent($content);
/**
* Process the content after the parsing has finished.
*
* @param string $content
* @return string
*/
public function afterParse($content);
/**
* Process the content after the stripping has finished.
*
* @param string $content
* @return string
*/
public function afterStrip($content);
/**
* Process the node's inner content before the filters are applied.
*
* @param string $content
* @return string
*/
public function beforeContent($content);
/**
* Process the content before the parsing begins.
*
* @param string $content
* @return string
*/
public function beforeParse($content);
/**
* Process the content before the stripping begins.
*
* @param string $content
* @return string
*/
public function beforeStrip($content);
/**
* Start up the Hook by initializing or loading any data before parsing begins.
*
* @return void
*/
public function startup();
/**
* Add any filter dependencies.
*
* @param \Decoda\Decoda $decoda
* @return \Decoda\Hook
*/
public function setupFilters(Decoda $decoda);
}

View File

@ -0,0 +1,75 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Hook;
use Decoda\Decoda;
use Decoda\Component\AbstractComponent;
use Decoda\Hook;
/**
* A hook allows you to inject functionality during certain events in the parsing cycle.
*/
abstract class AbstractHook extends AbstractComponent implements Hook {
/**
* {@inheritdoc}
*/
public function afterContent($content) {
return $content;
}
/**
* {@inheritdoc}
*/
public function afterParse($content) {
return $content;
}
/**
* {@inheritdoc}
*/
public function afterStrip($content) {
return $content;
}
/**
* {@inheritdoc}
*/
public function beforeContent($content) {
return $content;
}
/**
* {@inheritdoc}
*/
public function beforeParse($content) {
return $content;
}
/**
* {@inheritdoc}
*/
public function beforeStrip($content) {
return $content;
}
/**
* {@inheritdoc}
*/
public function startup() {
return;
}
/**
* {@inheritdoc}
*/
public function setupFilters(Decoda $decoda) {
return $this;
}
}

View File

@ -0,0 +1,170 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Hook;
use Decoda\Decoda;
use Decoda\Loader\FileLoader;
/**
* Censors words found within the censored.txt blacklist.
*/
class CensorHook extends AbstractHook {
/**
* List of words to censor.
*
* @type array
*/
protected $_blacklist = array();
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'suffix' => array('ing', 'in', 'er', 'r', 'ed', 'd')
);
/**
* Read the contents of the loaders into the emoticons list.
*/
public function startup() {
if ($this->_blacklist) {
return;
}
// Load files from config paths
foreach ($this->getParser()->getPaths() as $path) {
foreach (glob($path . 'censored.*') as $file) {
$this->addLoader(new FileLoader($file));
}
}
// Load the contents into the blacklist
foreach ($this->getLoaders() as $loader) {
$loader->setParser($this->getParser());
if ($blacklist = $loader->load()) {
$this->blacklist($blacklist);
}
}
}
/**
* Parse the content by censoring blacklisted words.
*
* @param string $content
* @return string
*/
public function beforeParse($content) {
return $this->_censor($content);
}
/**
* Parse the content by censoring blacklisted words.
*
* @param string $content
* @return string
*/
public function beforeStrip($content) {
return $this->_censor($content);
}
/**
* Add words to the blacklist.
*
* @param array $words
* @return \Decoda\Hook\CensorHook
*/
public function blacklist(array $words) {
$this->_blacklist = array_map('trim', array_filter($words)) + $this->_blacklist;
$this->_blacklist = array_unique($this->_blacklist);
return $this;
}
/**
* Return the current blacklist.
*
* @return array
*/
public function getBlacklist() {
return $this->_blacklist;
}
/**
* Trigger censoring.
*
* @param string $content
* @return string
*/
protected function _censor($content) {
$pattern = implode('|', array_map(array($this, '_prepareRegex'), $this->getBlacklist()));
$content = preg_replace_callback('/(?:^|\b)(?:' . $pattern . ')(?:\b|$)/is', array($this, '_censorCallback'), $content);
return $content;
}
/**
* Censor a word if its only by itself.
*
* @param array $matches
* @return string
*/
protected function _censorCallback($matches) {
$length = mb_strlen(trim($matches[0]));
$censored = '';
$symbols = str_shuffle('*@#$*!?%');
$i = 0;
$s = 0;
if ($length > 10) {
$length = 10;
}
while ($i < $length) {
$censored .= $symbols[$s];
$i++;
$s++;
if ($s > 7) {
$s = 0;
}
}
return $censored;
}
/**
* Prepare the regex pattern for each word.
*
* @param string $word
* @return string
*/
protected function _prepareRegex($word) {
$letters = str_split($word);
$regex = '';
foreach ($letters as $letter) {
$regex .= preg_quote($letter, '/') . '+';
}
$suffix = $this->getConfig('suffix');
if (is_array($suffix)) {
$suffix = implode('|', $suffix);
}
$regex .= '(?:' . $suffix . ')?';
return $regex;
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Hook;
use Decoda\Hook\AbstractHook;
/**
* Converts URLs and emails (not wrapped in tags) into clickable links.
*/
class ClickableHook extends AbstractHook {
/**
* Matches a link or an email, and converts it to an anchor tag.
*
* @param string $content
* @return string
*/
public function afterParse($content) {
$parser = $this->getParser();
// Janky way of detecting if a link is wrapped in an anchor tag
// We have to check the values before the link and validate them
// If quotes or a closing carrot exist, do not wrap
// <br> is acceptable since \n are completely removed
if ($parser->hasFilter('Url')) {
$protocols = $parser->getFilter('Url')->getConfig('protocols');
$chars = preg_quote('-_=+|\;:&?/[]%,.!@#$*(){}"\'', '/');
$pattern = implode('', array(
'(' . implode('|', $protocols) . ')s?:\/\/', // protocol
'([\w\.\+]+:[\w\.\+]+@)?', // login
'([\w\.]{5,255}+)', // domain, tld
'(:[0-9]{0,6}+)?', // port
'([a-z0-9' . $chars . ']+)?', // query
'(#[a-z0-9' . $chars . ']+)?' // fragment
));
$content = preg_replace_callback('/("|\'|>|<br>|<br\/>)?(' . $pattern . ')/is', array($this, '_urlCallback'), $content);
}
// Based on schema: http://en.wikipedia.org/wiki/Email_address
if ($parser->hasFilter('Email')) {
$pattern = '/("|\'|>|:|<br>|<br\/>)?(([-a-z0-9\.\+!]{1,64}+)@([-a-z0-9]+\.[a-z\.]+))/is';
$content = preg_replace_callback($pattern, array($this, '_emailCallback'), $content);
}
return $content;
}
/**
* Callback for email processing.
*
* @param array $matches
* @return string
*/
protected function _emailCallback($matches) {
if ($matches[1] === '<br>' || $matches[1] === '<br/>') {
$matches[0] = $matches[2];
} else if ($matches[1] !== '') {
return $matches[0];
}
return $matches[1] . $this->getParser()->getFilter('Email')->parse(array(
'tag' => 'email',
'attributes' => array()
), trim($matches[0]));
}
/**
* Callback for URL processing.
*
* @param array $matches
* @return string
*/
protected function _urlCallback($matches) {
if ($matches[1] === '<br>' || $matches[1] === '<br/>') {
$matches[0] = $matches[2];
} else if ($matches[1] !== '') {
return $matches[0];
}
return $matches[1] . $this->getParser()->getFilter('Url')->parse(array(
'tag' => 'url',
'attributes' => array()
), trim($matches[0]));
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Hook;
/**
* Encodes and decodes [code] blocks so that the inner content doesn't get processed.
*/
class CodeHook extends AbstractHook {
/**
* Encode code blocks before parsing. It use regexp (?R) recursivity mask to deal with other nested code tags
* see http://php.net/manual/en/regexp.reference.recursive.php and http://stackoverflow.com/questions/2909588/regex-bbcode-perfecting-nested-quote#answer-2909930 for more informations
*
* @param string $string
* @return mixed
*/
public function beforeParse($string) {
return preg_replace_callback('/\[code(.*?)\](((?R)|.)*?)\[\/code\]/is', array($this, '_encodeCallback'), $string);
}
/**
* Decode code blocks after parsing.
*
* @param string $string
* @return mixed
*/
public function afterParse($string) {
return preg_replace_callback('/\<pre(.*?)><code>(.*?)<\/code>\<\/pre>/is', array($this, '_decodeCallback'), $string);
}
/**
* Encode content using base64.
*
* @param array $matches
* @return string
*/
protected function _encodeCallback(array $matches) {
return '[code' . $matches[1] . ']' . base64_encode($matches[2]) . '[/code]';
}
/**
* Decode content using base64.
*
* @param array $matches
* @return string
*/
protected function _decodeCallback(array $matches) {
return '<pre' . $matches[1] . '><code>' . base64_decode($matches[2]) . '</code></pre>';
}
}

View File

@ -0,0 +1,169 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Hook;
use Decoda\Decoda;
use Decoda\Loader\FileLoader;
/**
* Converts smiley faces into emoticon images.
*/
class EmoticonHook extends AbstractHook {
/**
* Configuration.
*
* @type array
*/
protected $_config = array(
'path' => '/images/',
'extension' => 'png'
);
/**
* Mapping of emoticons to smilies.
*
* @type array
*/
protected $_emoticons = array();
/**
* Map of smilies to emoticons.
*
* @type array
*/
protected $_smilies = array();
/**
* Read the contents of the loaders into the emoticons list.
*/
public function startup() {
if ($this->_emoticons) {
return;
}
// Load files from config paths
foreach ($this->getParser()->getPaths() as $path) {
foreach (glob($path . 'emoticons.*') as $file) {
$this->addLoader(new FileLoader($file));
}
}
// Load the contents into the emoticon and smiley list
foreach ($this->getLoaders() as $loader) {
$loader->setParser($this->getParser());
if ($emoticons = $loader->load()) {
foreach ($emoticons as $emoticon => $smilies) {
foreach ($smilies as $smile) {
$this->_smilies[$smile] = $emoticon;
}
}
$this->_emoticons = array_merge($this->_emoticons, $emoticons);
}
}
}
/**
* Parse out the emoticons and replace with images.
*
* @param string $content
* @return string
*/
public function beforeContent($content) {
$smilies = $this->getSmilies();
// Build the smilies regex
$smiliesRegex = implode('|', array_map(function ($smile) {
return preg_quote($smile, '/');
}, $smilies));
$pattern = sprintf('/(?P<left>^|\n|\s)(?:%s)(?P<right>\n|\s|$)/is', $smiliesRegex);
// Make two passes to accept that one delimiter can use two smilies
$content = preg_replace_callback($pattern, array($this, '_emoticonCallback'), $content);
$content = preg_replace_callback($pattern, array($this, '_emoticonCallback'), $content);
return $content;
}
/**
* Gets the mapping of emoticons and smilies.
*
* @return array
*/
public function getEmoticons() {
return $this->_emoticons;
}
/**
* Returns all available smilies.
*
* @return array
*/
public function getSmilies() {
return array_keys($this->_smilies);
}
/**
* Checks if a smiley is set for the given id.
*
* @param string $smiley
* @return bool
*/
public function hasSmiley($smiley) {
return isset($this->_smilies[$smiley]);
}
/**
* Convert a smiley to an HTML representation.
*
* @param string $smiley
* @param bool $isXhtml
* @return string
*/
public function render($smiley, $isXhtml = true) {
if (!$this->hasSmiley($smiley)) {
return null;
}
$path = sprintf('%s%s.%s',
$this->getConfig('path'),
$this->_smilies[$smiley],
$this->getConfig('extension'));
if ($isXhtml) {
$tpl = '<img src="%s" alt="" />';
} else {
$tpl = '<img src="%s" alt="">';
}
return sprintf($tpl, $path);
}
/**
* Callback for smiley processing.
*
* @param array $matches
* @return string
*/
protected function _emoticonCallback($matches) {
$smiley = trim($matches[0]);
if (count($matches) === 1 || !$this->hasSmiley($smiley)) {
return $matches[0];
}
$l = isset($matches['left']) ? $matches['left'] : '';
$r = isset($matches['right']) ? $matches['right'] : '';
return $l . $this->render($smiley, $this->getParser()->getConfig('xhtmlOutput')) . $r;
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Hook;
/**
* An empty hook used for no operation events.
*/
class EmptyHook extends AbstractHook {
}

View File

@ -0,0 +1,22 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda;
/**
* Defines the methods for all resource Loaders to implement.
*/
interface Loader extends Component {
/**
* Load the resources contents.
*
* @return array
*/
public function load();
}

View File

@ -0,0 +1,18 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Loader;
use Decoda\Component\AbstractComponent;
use Decoda\Loader;
/**
* Abstract resource Loader that extends the Component layer.
*/
abstract class AbstractLoader extends AbstractComponent implements Loader {
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Loader;
/**
* A resource loader that returns data passed directly through the constructor.
*/
class DataLoader extends AbstractLoader {
/**
* Raw data.
*
* @type mixed
*/
protected $_data;
/**
* Store the data directly for later use.
*
* @param mixed $data
*/
public function __construct($data) {
$this->_data = $data;
}
/**
* Load the data.
*
* @return array
*/
public function load() {
return (array) $this->_data;
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
namespace Decoda\Loader;
use \Decoda\Exception\IoException;
use \Decoda\Exception\UnsupportedTypeException;
/**
* A resource loader for files on the local system.
*/
class FileLoader extends AbstractLoader {
/**
* Path to file.
*
* @type string
*/
protected $_path;
/**
* Store the path and validate the files existence.
*
* @param string $path
* @throws \Decoda\Exception\IoException
*/
public function __construct($path) {
if (!file_exists($path)) {
throw new IoException(sprintf('File %s does not exist', $path));
}
$this->_path = $path;
}
/**
* Load the resources contents.
*
* @return array
* @throws \Decoda\Exception\UnsupportedTypeException
*/
public function load() {
$ext = mb_strtolower(pathinfo($this->_path, PATHINFO_EXTENSION));
switch ($ext) {
case 'php':
return include $this->_path;
break;
case 'json':
return json_decode(file_get_contents($this->_path), true);
break;
case 'ini':
return parse_ini_file($this->_path, true);
break;
case 'txt':
return file($this->_path, FILE_IGNORE_NEW_LINES);
break;
}
throw new UnsupportedTypeException(sprintf('Unsupported FileLoader file type %s', $ext));
}
}

58
web/third_party/Decoda/autoloader.php vendored Normal file
View File

@ -0,0 +1,58 @@
<?php
/**
* File: autoloader.php.
* Author: Ulrich Block
* Date: 02.11.15
* Time: 21:27
* Contact: <ulrich.block@easy-wi.com>
*
* This file is part of Easy-WI.
*
* Easy-WI is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Easy-WI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Easy-WI. If not, see <http://www.gnu.org/licenses/>.
*
* Diese Datei ist Teil von Easy-WI.
*
* Easy-WI ist Freie Software: Sie koennen es unter den Bedingungen
* der GNU General Public License, wie von der Free Software Foundation,
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder spaeteren
* veroeffentlichten Version, weiterverbreiten und/oder modifizieren.
*
* Easy-WI wird in der Hoffnung, dass es nuetzlich sein wird, aber
* OHNE JEDE GEWAEHELEISTUNG, bereitgestellt; sogar ohne die implizite
* Gewaehrleistung der MARKTFAEHIGKEIT oder EIGNUNG FUER EINEN BESTIMMTEN ZWECK.
* Siehe die GNU General Public License fuer weitere Details.
*
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
* Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>.
*/
spl_autoload_register(function ($class) {
$prefix = 'Decoda\\';
$length = strlen($prefix);
if (strncmp($prefix, $class, $length) !== 0) {
return;
}
$relativeClass = substr($class, $length);
$file = EASYWIDIR . '/third_party/Decoda/Decoda/' . str_replace('\\', '/', $relativeClass) . '.php';
if (file_exists($file)) {
require $file;
}
});

View File

@ -0,0 +1,48 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
return array(
'asshole',
'bitch',
'btch',
'blowjob',
'cock',
'cawk',
'clt',
'clit',
'clitoris',
'cock',
'cocksucker',
'cum',
'cunt',
'cnt',
'dildo',
'dick',
'douche',
'fag',
'faggot',
'fcuk',
'fuck',
'fuk',
'motherfucker',
'nigga',
'nigger',
'nig',
'penis',
'pussy',
'rimjaw',
'scrotum',
'shit',
'sht',
'slut',
'twat',
'whore',
'whre',
'vagina',
'vag',
'rape',
);

View File

@ -0,0 +1,29 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
/**
* Mapping of emoticons to a list of smilies that represents it.
* The smiley will be replaced with an image that uses the emoticon name.
*/
return array(
'angry' => array('&gt;(', '&gt;:(', '&gt;[', '&gt;:[', ':angry:'),
'aw' => array(':aw:'),
'cool' => array('8)', '8]', ':cool:'),
'ecstatic' => array(':D', '8D', ':ecstatic:'),
'furious' => array('&gt;:D', '&gt;&lt;', ':furious:'),
'gah' => array('D:', ':O', ':gah:'),
'happy' => array(':)', ':]', ':happy:'),
'heart' => array('&lt;3', ':heart:'),
'hm' => array(':/', ':\\', ':hm:'),
'kiss' => array(':3', ':kiss:'),
'meh' => array(':|', '-.-', '&lt;_&lt;', '&gt;_&gt;', ':meh:'),
'mmf' => array(':x', ':X', ':mmf:'),
'sad' => array(':(', ':[', ';(', ';[', ':\'(', ':\'[', ';\'(', ';\'[', ':sad:'),
'tongue' => array(':P', ':p', ':tongue:'),
'what' => array(':o', ':?', ':what:'),
'wink' => array(';)', ';]', ';D', ':wink:'),
);

View File

@ -0,0 +1,137 @@
<?php
/**
* @copyright 2006-2014, Miles Johnson - http://milesj.me
* @license https://github.com/milesj/decoda/blob/master/license.md
* @link http://milesj.me/code/php/decoda
*/
return array(
'en-us' => array(
'spoiler' => 'Spoiler',
'hide' => 'Hide',
'show' => 'Show',
'link' => 'link',
'mail' => 'mail',
'quoteBy' => 'Quote by {author}',
),
'es-mx' => array(
'spoiler' => 'Spoiler',
'hide' => 'Ocultar',
'show' => 'Mostrar',
'link' => 'enlace',
'mail' => 'correo',
'quoteBy' => '{author} escribió:',
),
'fr-fr' => array(
'spoiler' => 'Spoiler',
'hide' => 'Cacher',
'show' => 'Afficher',
'link' => 'lien',
'mail' => 'email',
'quoteBy' => 'Citation de {author}',
),
'it-it' => array(
'spoiler' => 'Spoiler',
'hide' => 'Nascondere',
'show' => 'Spettacolo',
'link' => 'collegamento',
'mail' => 'posta',
'quoteBy' => 'Quote da {author}',
),
'nl-nl' => array(
'spoiler' => 'Spoiler',
'hide' => 'Verberg',
'show' => 'Toon',
'link' => 'link',
'mail' => 'mail',
'quoteBy' => 'Quote door {author}',
),
'de-de' => array(
'spoiler' => 'Spoiler',
'hide' => 'Verstecke',
'show' => 'Zeige',
'link' => 'link',
'mail' => 'mail',
'quoteBy' => '{author} schrieb:',
),
'sv-se' => array(
'spoiler' => 'Spoiler',
'hide' => 'Dölja',
'show' => 'Visa',
'link' => 'länk',
'mail' => 'e-post',
'quoteBy' => 'Citat från {author}',
),
'el-gr' => array(
'spoiler' => 'αεροτομή',
'hide' => 'Απόκρυψη',
'show' => 'Εμφάνιση',
'link' => 'σύνδεσμος',
'mail' => 'ταχυδρομείο',
'quoteBy' => 'Παράθεση από {author}',
),
'bg-bg' => array(
'spoiler' => 'спойлер',
'hide' => 'крия',
'show' => 'шоу',
'link' => 'връзка',
'mail' => 'поща',
'quoteBy' => 'цитат от {author}',
),
'ru-ru' => array(
'spoiler' => 'спойлер',
'hide' => 'скрыть',
'show' => 'показать',
'link' => 'ссылка',
'mail' => 'электронная почта',
'quoteBy' => '{author} написал:',
),
'zh-cn' => array(
'spoiler' => '扰流板',
'hide' => '隐藏',
'show' => '显示',
'link' => '链接',
'mail' => '电子邮件',
'quoteBy' => '引用由 {author}',
),
'ja-jp' => array(
'spoiler' => 'スポイラー',
'hide' => '隠す',
'show' => '表示',
'link' => 'のリンク',
'mail' => 'メール',
'quoteBy' => '{author}によって引用',
),
'ko-kr' => array(
'spoiler' => '스포일러',
'hide' => '숨기기',
'show' => '표시',
'link' => '링크',
'mail' => '우편',
'quoteBy' => '{author}에 의해 견적',
),
'id-id' => array(
'spoiler' => 'Spoiler',
'hide' => 'Menyembunyikan',
'show' => 'Tampilkan',
'link' => 'link',
'mail' => 'email',
'quoteBy' => 'Quote by {author}',
),
'hu-hu' => array(
'spoiler' => 'Spoiler',
'hide' => 'Rejt',
'show' => 'Mutat',
'link' => 'link',
'mail' => 'mail',
'quoteBy' => 'Idézve {author}',
),
'tr-tr' => array(
'spoiler' => 'Spoiler',
'hide' => 'Gizle',
'show' => 'Göster',
'link' => 'link',
'mail' => 'mail',
'quoteBy' => '{author} tarafından yazılan',
),
);

View File

@ -0,0 +1,3 @@
<?php // Place $content directly within the tags to not leave any whitespace for <pre> ?>
<pre class="decoda-code<?php if (!empty($lang)) { echo ' ' . $classPrefix . $lang; } ?>"<?php if (!empty($hl)) { printf(' %s="%s"', $highlightAttribute, $hl); } ?>><code><?php echo $content; ?></code></pre>

View File

@ -0,0 +1,25 @@
<blockquote class="decoda-quote">
<?php if (!empty($author) || !empty($date)) { ?>
<div class="decoda-quote-head">
<?php if (!empty($date)) { ?>
<span class="decoda-quote-date">
<?php echo date($dateFormat, is_numeric($date) ? $date : strtotime($date)); ?>
</span>
<?php }
if (!empty($author)) { ?>
<span class="decoda-quote-author">
<?php echo $this->getFilter()->message('quoteBy', array(
'author' => $this->escape($author)
)); ?>
</span>
<?php } ?>
<span class="clear"></span>
</div>
<?php } ?>
<div class="decoda-quote-body">
<?php echo $content; ?>
</div>
</blockquote>

View File

@ -0,0 +1,13 @@
<?php
$counter = rand();
$filter = $this->getFilter();
$show = $filter->message('spoiler') . ' (' . $filter->message('show') . ')';
$hide = $filter->message('spoiler') . ' (' . $filter->message('hide') . ')'; ?>
<div class="decoda-spoiler">
<button class="decoda-spoiler-button" type="button" onclick="<?php echo str_replace('{id}', $counter, $spoilerToggle); ?>"><?php echo $show; ?></button>
<div class="decoda-spoiler-content" id="spoiler-content-<?php echo $counter; ?>" style="display: none">
<?php echo $content; ?>
</div>
</div>

View File

@ -0,0 +1,5 @@
<?php if ($player === 'embed') { ?>
<embed src="<?php echo $url; ?>" width="<?php echo $width; ?>" height="<?php echo $height; ?>" type="application/x-shockwave-flash"></embed>
<?php } else { ?>
<iframe src="<?php echo $url; ?>" width="<?php echo $width; ?>" height="<?php echo $height; ?>" frameborder="0"></iframe>
<?php } ?>