commit
3577412930
57 changed files with 3794 additions and 11 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -2,3 +2,9 @@
|
||||||
*
|
*
|
||||||
!/**/
|
!/**/
|
||||||
!*.*
|
!*.*
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
tmp/*
|
||||||
|
|
||||||
|
!*.gitkeep
|
||||||
|
|
48
.phpcs.xml.dist
Normal file
48
.phpcs.xml.dist
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="WordPress Coding Standards based custom ruleset for your plugin">
|
||||||
|
<description>Generally-applicable sniffs for WordPress plugins.</description>
|
||||||
|
|
||||||
|
<!-- What to scan -->
|
||||||
|
<file>.</file>
|
||||||
|
<exclude-pattern>/vendor/</exclude-pattern>
|
||||||
|
|
||||||
|
<!-- How to scan -->
|
||||||
|
<!-- Usage instructions: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage -->
|
||||||
|
<!-- Annotated ruleset: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
|
||||||
|
<arg value="sp"/> <!-- Show sniff and progress -->
|
||||||
|
<arg name="basepath" value="./"/><!-- Strip the file paths down to the relevant bit -->
|
||||||
|
<arg name="colors"/>
|
||||||
|
<arg name="extensions" value="php"/>
|
||||||
|
<arg name="parallel" value="8"/><!-- Enables parallel processing when available for faster results. -->
|
||||||
|
|
||||||
|
<!-- Rules: Check PHP version compatibility -->
|
||||||
|
<!-- https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions -->
|
||||||
|
<config name="testVersion" value="5.3-"/>
|
||||||
|
<!-- https://github.com/PHPCompatibility/PHPCompatibilityWP -->
|
||||||
|
<rule ref="PHPCompatibilityWP"/>
|
||||||
|
|
||||||
|
<!-- Rules: WordPress Coding Standards -->
|
||||||
|
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards -->
|
||||||
|
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties -->
|
||||||
|
<config name="minimum_supported_wp_version" value="4.6"/>
|
||||||
|
<rule ref="WordPress">
|
||||||
|
<exclude name="WordPress.VIP"/>
|
||||||
|
</rule>
|
||||||
|
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
|
||||||
|
<properties>
|
||||||
|
<!-- Value: replace the function, class, and variable prefixes used. Separate multiple prefixes with a comma. -->
|
||||||
|
<property name="prefixes" type="array" value="my-plugin"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
<rule ref="WordPress.WP.I18n">
|
||||||
|
<properties>
|
||||||
|
<!-- Value: replace the text domain used. -->
|
||||||
|
<property name="text_domain" type="array" value="my-plugin"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
<rule ref="WordPress.WhiteSpace.ControlStructureSpacing">
|
||||||
|
<properties>
|
||||||
|
<property name="blank_line_check" value="true"/>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
</ruleset>
|
65
.travis.yml
Normal file
65
.travis.yml
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
sudo: false
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
language: php
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: never
|
||||||
|
on_failure: change
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.composer/cache
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php: 7.2
|
||||||
|
env: WP_VERSION=latest
|
||||||
|
- php: 7.1
|
||||||
|
env: WP_VERSION=latest
|
||||||
|
- php: 7.0
|
||||||
|
env: WP_VERSION=latest
|
||||||
|
- php: 5.6
|
||||||
|
env: WP_VERSION=latest
|
||||||
|
- php: 5.6
|
||||||
|
env: WP_VERSION=trunk
|
||||||
|
- php: 5.6
|
||||||
|
env: WP_TRAVISCI=phpcs
|
||||||
|
- php: 5.3
|
||||||
|
env: WP_VERSION=latest
|
||||||
|
dist: precise
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- export PATH="$HOME/.composer/vendor/bin:$PATH"
|
||||||
|
- |
|
||||||
|
if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then
|
||||||
|
phpenv config-rm xdebug.ini
|
||||||
|
else
|
||||||
|
echo "xdebug.ini does not exist"
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [[ ! -z "$WP_VERSION" ]] ; then
|
||||||
|
bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
|
||||||
|
composer global require "phpunit/phpunit=4.8.*|5.7.*"
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
|
||||||
|
composer global require wp-coding-standards/wpcs
|
||||||
|
phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs
|
||||||
|
fi
|
||||||
|
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
if [[ ! -z "$WP_VERSION" ]] ; then
|
||||||
|
phpunit
|
||||||
|
WP_MULTISITE=1 phpunit
|
||||||
|
fi
|
||||||
|
- |
|
||||||
|
if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
|
||||||
|
phpcs
|
||||||
|
fi
|
152
bin/install-wp-tests.sh
Executable file
152
bin/install-wp-tests.sh
Executable file
|
@ -0,0 +1,152 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ $# -lt 3 ]; then
|
||||||
|
echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DB_NAME=$1
|
||||||
|
DB_USER=$2
|
||||||
|
DB_PASS=$3
|
||||||
|
DB_HOST=${4-localhost}
|
||||||
|
WP_VERSION=${5-latest}
|
||||||
|
SKIP_DB_CREATE=${6-false}
|
||||||
|
|
||||||
|
TMPDIR=${TMPDIR-/tmp}
|
||||||
|
TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
|
||||||
|
WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
|
||||||
|
WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/}
|
||||||
|
|
||||||
|
download() {
|
||||||
|
if [ `which curl` ]; then
|
||||||
|
curl -s "$1" > "$2";
|
||||||
|
elif [ `which wget` ]; then
|
||||||
|
wget -nv -O "$2" "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
WP_TESTS_TAG="branches/$WP_VERSION"
|
||||||
|
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||||
|
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
||||||
|
# version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
|
||||||
|
WP_TESTS_TAG="tags/${WP_VERSION%??}"
|
||||||
|
else
|
||||||
|
WP_TESTS_TAG="tags/$WP_VERSION"
|
||||||
|
fi
|
||||||
|
elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
||||||
|
WP_TESTS_TAG="trunk"
|
||||||
|
else
|
||||||
|
# http serves a single offer, whereas https serves multiple. we only want one
|
||||||
|
download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
|
||||||
|
grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
|
||||||
|
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
|
||||||
|
if [[ -z "$LATEST_VERSION" ]]; then
|
||||||
|
echo "Latest WordPress version could not be found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
WP_TESTS_TAG="tags/$LATEST_VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
install_wp() {
|
||||||
|
|
||||||
|
if [ -d $WP_CORE_DIR ]; then
|
||||||
|
return;
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p $WP_CORE_DIR
|
||||||
|
|
||||||
|
if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
|
||||||
|
mkdir -p $TMPDIR/wordpress-nightly
|
||||||
|
download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip
|
||||||
|
unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/
|
||||||
|
mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR
|
||||||
|
else
|
||||||
|
if [ $WP_VERSION == 'latest' ]; then
|
||||||
|
local ARCHIVE_NAME='latest'
|
||||||
|
elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
|
||||||
|
# https serves multiple offers, whereas http serves single.
|
||||||
|
download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
|
||||||
|
if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
|
||||||
|
# version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
|
||||||
|
LATEST_VERSION=${WP_VERSION%??}
|
||||||
|
else
|
||||||
|
# otherwise, scan the releases and get the most up to date minor version of the major release
|
||||||
|
local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
|
||||||
|
LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
|
||||||
|
fi
|
||||||
|
if [[ -z "$LATEST_VERSION" ]]; then
|
||||||
|
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
||||||
|
else
|
||||||
|
local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
local ARCHIVE_NAME="wordpress-$WP_VERSION"
|
||||||
|
fi
|
||||||
|
download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
|
||||||
|
tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
|
||||||
|
}
|
||||||
|
|
||||||
|
install_test_suite() {
|
||||||
|
# portable in-place argument for both GNU sed and Mac OSX sed
|
||||||
|
if [[ $(uname -s) == 'Darwin' ]]; then
|
||||||
|
local ioption='-i.bak'
|
||||||
|
else
|
||||||
|
local ioption='-i'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set up testing suite if it doesn't yet exist
|
||||||
|
if [ ! -d $WP_TESTS_DIR ]; then
|
||||||
|
# set up testing suite
|
||||||
|
mkdir -p $WP_TESTS_DIR
|
||||||
|
svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
|
||||||
|
svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f wp-tests-config.php ]; then
|
||||||
|
download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
# remove all forward slashes in the end
|
||||||
|
WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
|
||||||
|
sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
install_db() {
|
||||||
|
|
||||||
|
if [ ${SKIP_DB_CREATE} = "true" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# parse DB_HOST for port or socket references
|
||||||
|
local PARTS=(${DB_HOST//\:/ })
|
||||||
|
local DB_HOSTNAME=${PARTS[0]};
|
||||||
|
local DB_SOCK_OR_PORT=${PARTS[1]};
|
||||||
|
local EXTRA=""
|
||||||
|
|
||||||
|
if ! [ -z $DB_HOSTNAME ] ; then
|
||||||
|
if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
|
||||||
|
EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
|
||||||
|
elif ! [ -z $DB_SOCK_OR_PORT ] ; then
|
||||||
|
EXTRA=" --socket=$DB_SOCK_OR_PORT"
|
||||||
|
elif ! [ -z $DB_HOSTNAME ] ; then
|
||||||
|
EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create database
|
||||||
|
mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
|
||||||
|
}
|
||||||
|
|
||||||
|
install_wp
|
||||||
|
install_test_suite
|
||||||
|
install_db
|
|
@ -80,6 +80,42 @@ class LBRY_Daemon
|
||||||
return $result->result;
|
return $result->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes a post to the LBRY Network
|
||||||
|
* @param string $name The slug for the post
|
||||||
|
* @param float $bid The amount of LBC to bid
|
||||||
|
* @param string $filepath The path of the temporary content file
|
||||||
|
* @param string $title The Title of the post
|
||||||
|
* @param string $description The Description of the Post
|
||||||
|
* @param string $language Two letter ISO Code of the language
|
||||||
|
* @return string $channel The Claim ID of the Channel
|
||||||
|
*/
|
||||||
|
public function publish($name, $bid, $filepath, $title, $description, $language, $channel)
|
||||||
|
{
|
||||||
|
$args = array(
|
||||||
|
'name' => $name,
|
||||||
|
'bid' => $bid,
|
||||||
|
'file_path' => $filepath,
|
||||||
|
'title' => $title,
|
||||||
|
'description' => $description,
|
||||||
|
'language' => $language,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Make sure we aren't publishing to unattributed
|
||||||
|
if ($channel != 'null') {
|
||||||
|
$args['channel_id'] = $channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Bring thumbnails into the mix
|
||||||
|
$result = $this->request(
|
||||||
|
'publish',
|
||||||
|
$args
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->check_for_errors($result);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a cURL request to the LBRY Daemon
|
* Sends a cURL request to the LBRY Daemon
|
||||||
* @param string $method The method to call on the LBRY API
|
* @param string $method The method to call on the LBRY API
|
||||||
|
|
|
@ -7,10 +7,103 @@
|
||||||
|
|
||||||
class LBRY_Network
|
class LBRY_Network
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Publishing Object
|
||||||
|
* @var LBRY_Network_Publisher
|
||||||
|
*/
|
||||||
|
public $publisher = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Parsing Object
|
||||||
|
* @var LBRY_Network_Parser
|
||||||
|
*/
|
||||||
|
public $parser = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [__construct description]
|
* [__construct description]
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
$this->publisher = new LBRY_Network_Publisher();
|
||||||
|
$this->parser = new LBRY_Network_Parser();
|
||||||
|
|
||||||
|
$this->post_meta_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up everything for the post meta boxes
|
||||||
|
*/
|
||||||
|
private function post_meta_setup()
|
||||||
|
{
|
||||||
|
// Add the meta boxes
|
||||||
|
add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
|
||||||
|
|
||||||
|
// Save the post meta on 'save_post' hook
|
||||||
|
add_action('save_post', array($this, 'save_post_meta'), 10, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the meta boxes to the post editing backend
|
||||||
|
*/
|
||||||
|
public function add_meta_boxes()
|
||||||
|
{
|
||||||
|
// TODO: Support post types based on user selection
|
||||||
|
add_meta_box(
|
||||||
|
'lbry-network-publishing', // Unique ID
|
||||||
|
'LBRY Network', // Title
|
||||||
|
array($this, 'meta_box_html'), // Callback function
|
||||||
|
'post', // Screen Options (or post type)
|
||||||
|
'side', // Context
|
||||||
|
'high' // Priority
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles saving the post meta that is relative to publishing to the LBRY Network
|
||||||
|
* @param int $post_id The ID of the post we are saving
|
||||||
|
* @param WP_Post $post The Post Object we are saving
|
||||||
|
* @return int Returns post_id if user cannot edit post
|
||||||
|
*/
|
||||||
|
public function save_post_meta($post_id, $post)
|
||||||
|
{
|
||||||
|
// Verify the nonce before proceeding.
|
||||||
|
if (!isset($_POST['_lbrynonce']) || !wp_verify_nonce($_POST['_lbrynonce'], 'lbry_publish_channels')) {
|
||||||
|
return $post_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the current user has permission to edit the post.
|
||||||
|
$post_type = get_post_type_object($post->post_type);
|
||||||
|
if (!current_user_can($post_type->cap->edit_post, $post_id)) {
|
||||||
|
return $post_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$will_publish = (isset($_POST[LBRY_WILL_PUBLISH]) ? $_POST[LBRY_WILL_PUBLISH] : false);
|
||||||
|
$new_channel = (isset($_POST[LBRY_POST_CHANNEL]) ? $_POST[LBRY_POST_CHANNEL] : null);
|
||||||
|
$cur_channel = get_post_meta($post_id, LBRY_POST_CHANNEL, true);
|
||||||
|
|
||||||
|
// Update meta acordingly
|
||||||
|
if (!$will_publish) {
|
||||||
|
update_post_meta($post_id, LBRY_WILL_PUBLISH, 'false');
|
||||||
|
} else {
|
||||||
|
update_post_meta($post_id, LBRY_WILL_PUBLISH, 'true');
|
||||||
|
}
|
||||||
|
if ($new_channel !== $cur_channel) {
|
||||||
|
update_post_meta($post_id, LBRY_POST_CHANNEL, $new_channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($will_publish) {
|
||||||
|
// Publish the post on the LBRY Network
|
||||||
|
$this->publisher->publish($post, get_post_meta($post_id, LBRY_POST_CHANNEL, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTML for the LBRY Meta Box
|
||||||
|
* @param [type] $post [description]
|
||||||
|
*/
|
||||||
|
public function meta_box_html($post)
|
||||||
|
{
|
||||||
|
require_once(LBRY_ABSPATH . 'templates/meta_box.php');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,45 @@
|
||||||
<?php
|
<?php
|
||||||
|
use League\HTMLToMarkdown\HtmlConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses wordpress posts to be ready for the LBRY Network
|
* Parses wordpress posts to be ready for the LBRY Network
|
||||||
|
* Uses the Html-to-Markdown package
|
||||||
|
* https://github.com/thephpleague/html-to-markdown
|
||||||
*
|
*
|
||||||
* @package LBRYPress
|
* @package LBRYPress
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class LBRY_Network_Parser
|
class LBRY_Network_Parser
|
||||||
{
|
{
|
||||||
/**
|
public $converter = null;
|
||||||
* [__construct description]
|
|
||||||
*/
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
// COMBAK: Composer is not safe in a wordpress environment. May have to write our own package.
|
||||||
|
require_once LBRY_ABSPATH . 'vendor/autoload.php';
|
||||||
|
$this->converter = new HtmlConverter(array(
|
||||||
|
'strip_tags' => true
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a post into markdown.
|
||||||
|
* @param WP_Post $post The post to be converted
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert_to_markdown($post)
|
||||||
|
{
|
||||||
|
// $title = '<h1>' . $post->post_title . '</h1>';
|
||||||
|
//
|
||||||
|
// $featured_image = get_the_post_thumbnail($post);
|
||||||
|
//
|
||||||
|
// $content = $title;
|
||||||
|
// if ($featured_image) {
|
||||||
|
// $content .= $featured_image . '<br />';
|
||||||
|
// }
|
||||||
|
$content = apply_filters('the_content', $post->post_content);
|
||||||
|
$converted = $this->converter->convert($content);
|
||||||
|
|
||||||
|
return $converted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,4 +13,47 @@ class LBRY_Network_Publisher
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish the post to the LBRY Network
|
||||||
|
* @param int $post_id The ID of the post we are publishing
|
||||||
|
* @param string $channel The Claim ID of the channel we are posting to
|
||||||
|
*/
|
||||||
|
public function publish($post, $channel)
|
||||||
|
{
|
||||||
|
// Leave if nothing to publish to
|
||||||
|
if (!$channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get converted markdown into a file
|
||||||
|
$filepath = LBRY_ABSPATH . 'tmp/' . $post->post_name . time() . '.md';
|
||||||
|
$file = fopen($filepath, 'w');
|
||||||
|
$converted = LBRY()->network->parser->convert_to_markdown($post);
|
||||||
|
$write_status = $file && fwrite($file, $converted);
|
||||||
|
fclose($file);
|
||||||
|
|
||||||
|
// TODO: Catch relative exceptions if necessary
|
||||||
|
try {
|
||||||
|
// If everything went well with the conversion, carry on
|
||||||
|
if ($write_status) {
|
||||||
|
$featured_image = get_the_post_thumbnail($post);
|
||||||
|
|
||||||
|
$name = $post->post_name;
|
||||||
|
$bid = floatval(get_option(LBRY_SETTINGS)[LBRY_LBC_PUBLISH]);
|
||||||
|
$title = $post->post_title;
|
||||||
|
$language = substr(get_locale(), 0, 2);
|
||||||
|
$license = get_option(LBRY_SETTINGS)[LBRY_LICENSE];
|
||||||
|
// TODO: See if we can grab from yoast or a default?
|
||||||
|
$description = $post->post_title;
|
||||||
|
// TODO: Bring thumbnails into the mix
|
||||||
|
// $thumbnail = $featured_image ? $featured_image : null;
|
||||||
|
|
||||||
|
LBRY()->daemon->publish($name, $bid, $filepath, $title, $description, $language, $channel);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// Delete the temporary markdown file
|
||||||
|
unlink($filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,11 @@ class LBRYPress
|
||||||
*/
|
*/
|
||||||
public $notice = null;
|
public $notice = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Library Network Object
|
||||||
|
*/
|
||||||
|
public $network = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main LBRYPress Instance.
|
* Main LBRYPress Instance.
|
||||||
*
|
*
|
||||||
|
@ -96,6 +101,8 @@ class LBRYPress
|
||||||
$this->define('LBRY_SPEECH', 'lbry_speech'); // the spee.ch address
|
$this->define('LBRY_SPEECH', 'lbry_speech'); // the spee.ch address
|
||||||
$this->define('LBRY_LICENSE', 'lbry_license'); // the license to publish with to the LBRY network
|
$this->define('LBRY_LICENSE', 'lbry_license'); // the license to publish with to the LBRY network
|
||||||
$this->define('LBRY_LBC_PUBLISH', 'lbry_lbc_publish'); // amount of lbc to use per publish
|
$this->define('LBRY_LBC_PUBLISH', 'lbry_lbc_publish'); // amount of lbc to use per publish
|
||||||
|
$this->define('LBRY_WILL_PUBLISH', 'lbry_will_publish'); // The meta key for if to publish to LBRY Network or not
|
||||||
|
$this->define('LBRY_POST_CHANNEL', 'lbry_channel'); // The meta key for which channel to publish
|
||||||
$this->define('LBRY_AVAILABLE_LICENSES', array(
|
$this->define('LBRY_AVAILABLE_LICENSES', array(
|
||||||
'mit' => 'MIT',
|
'mit' => 'MIT',
|
||||||
'license2' => 'License 2',
|
'license2' => 'License 2',
|
||||||
|
@ -123,7 +130,6 @@ class LBRYPress
|
||||||
{
|
{
|
||||||
$this->daemon = new LBRY_Daemon();
|
$this->daemon = new LBRY_Daemon();
|
||||||
$this->speech = new LBRY_Speech();
|
$this->speech = new LBRY_Speech();
|
||||||
$this->notice = new LBRY_Admin_Notice();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,6 +143,8 @@ class LBRYPress
|
||||||
// Admin request
|
// Admin request
|
||||||
if (is_admin()) {
|
if (is_admin()) {
|
||||||
$this->admin = new LBRY_Admin();
|
$this->admin = new LBRY_Admin();
|
||||||
|
$this->notice = new LBRY_Admin_Notice();
|
||||||
|
$this->network = new LBRY_Network();
|
||||||
} else {
|
} else {
|
||||||
$this->speech->maybe_rewrite_urls();
|
$this->speech->maybe_rewrite_urls();
|
||||||
}
|
}
|
||||||
|
@ -176,8 +184,6 @@ class LBRYPress
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// update_option(LBRY_SETTINGS, $new_settings);
|
// update_option(LBRY_SETTINGS, $new_settings);
|
||||||
|
|
||||||
error_log('Activated');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,4 +193,19 @@ class LBRYPress
|
||||||
{
|
{
|
||||||
error_log('Deactivated');
|
error_log('Deactivated');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility Functions
|
||||||
|
*/
|
||||||
|
public static function channel_name_comp($a, $b)
|
||||||
|
{
|
||||||
|
if ($a->name === $b->name) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($b->name == '(none / unattributed)') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return strnatcasecmp($a->name, $b->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
13
composer.json
Normal file
13
composer.json
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"name": "undergroundweblab/lbrypress",
|
||||||
|
"description": "A Wordpress plugin to connect to the LBRY Network",
|
||||||
|
"require": {
|
||||||
|
"league/html-to-markdown": "^4.8"
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Underground Web Lab",
|
||||||
|
"email": "paul@undergroundweblab.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
82
composer.lock
generated
Normal file
82
composer.lock
generated
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "cb08bd734b8d1da7ed57c572fa75e2d9",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "league/html-to-markdown",
|
||||||
|
"version": "4.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||||
|
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/f9a879a068c68ff47b722de63f58bec79e448f9d",
|
||||||
|
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||||
|
"phpunit/phpunit": "4.*",
|
||||||
|
"scrutinizer/ocular": "~1.1"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/html-to-markdown"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.9-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\HTMLToMarkdown\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nick Cernis",
|
||||||
|
"email": "nick@cern.is",
|
||||||
|
"homepage": "http://modernnerd.net",
|
||||||
|
"role": "Original Author"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Colin O'Dell",
|
||||||
|
"email": "colinodell@gmail.com",
|
||||||
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||||
|
"homepage": "https://github.com/thephpleague/html-to-markdown",
|
||||||
|
"keywords": [
|
||||||
|
"html",
|
||||||
|
"markdown"
|
||||||
|
],
|
||||||
|
"time": "2018-09-18T12:18:08+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": []
|
||||||
|
}
|
15
phpunit.xml.dist
Normal file
15
phpunit.xml.dist
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<phpunit
|
||||||
|
bootstrap="tests/bootstrap.php"
|
||||||
|
backupGlobals="false"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite>
|
||||||
|
<directory prefix="test-" suffix=".php">./tests/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
</phpunit>
|
43
templates/meta_box.php
Normal file
43
templates/meta_box.php
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
$unnatributed = (object) array(
|
||||||
|
'name' => '(none / unattributed)',
|
||||||
|
'claim_id' => 'null'
|
||||||
|
);
|
||||||
|
// TODO: Test what happens with empty channel list, can't remember the return value
|
||||||
|
$channels = LBRY()->daemon->channel_list();
|
||||||
|
$channels[] = $unnatributed;
|
||||||
|
// Sort the channels in a natural way
|
||||||
|
usort($channels, array('LBRYPress', 'channel_name_comp'));
|
||||||
|
$cur_channel = get_post_meta($post->ID, LBRY_POST_CHANNEL, true);
|
||||||
|
$will_publish = get_post_meta($post->ID, LBRY_WILL_PUBLISH, true);
|
||||||
|
?>
|
||||||
|
<?php wp_nonce_field('lbry_publish_channels', '_lbrynonce'); ?>
|
||||||
|
<div class="lbry-meta-checkbox-wrapper">
|
||||||
|
<label class="lbry-meta-label">
|
||||||
|
<input type="checkbox" class="lbry-meta-checkbox" name="<?= LBRY_WILL_PUBLISH ?>" value="true"
|
||||||
|
<?php
|
||||||
|
if ($will_publish === 'true' || $will_publish === '') {
|
||||||
|
echo 'checked';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
>
|
||||||
|
Sync this post on channel:
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<select class="lbry-meta-select" name="<?= LBRY_POST_CHANNEL ?>">
|
||||||
|
<?php foreach ($channels as $index=>$channel): ?>
|
||||||
|
<option value="<?= $channel->claim_id ?>"
|
||||||
|
<?php
|
||||||
|
if ($cur_channel) {
|
||||||
|
if ($cur_channel === $channel->claim_id) {
|
||||||
|
echo 'selected';
|
||||||
|
}
|
||||||
|
} elseif ($index === 0) {
|
||||||
|
echo 'selected';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
>
|
||||||
|
<?= $channel->name ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
|
@ -2,14 +2,12 @@
|
||||||
$LBRY = LBRY();
|
$LBRY = LBRY();
|
||||||
$wallet_balance = $LBRY->daemon->wallet_balance();
|
$wallet_balance = $LBRY->daemon->wallet_balance();
|
||||||
$channel_list = $LBRY->daemon->channel_list();
|
$channel_list = $LBRY->daemon->channel_list();
|
||||||
|
// TODO: Make this page look cleaner
|
||||||
?>
|
?>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
|
|
||||||
<h1><?= esc_html(get_admin_page_title()); ?></h1>
|
<h1><?= esc_html(get_admin_page_title()); ?></h1>
|
||||||
|
|
||||||
<h2>Your wallet amount:</h2>
|
<h2>Your wallet amount:</h2>
|
||||||
<code><?= number_format($wallet_balance, 2, '.', ','); ?></code>
|
<code><?= number_format($wallet_balance, 2, '.', ','); ?></code>
|
||||||
|
|
||||||
<form action="options.php" method="post">
|
<form action="options.php" method="post">
|
||||||
<?php
|
<?php
|
||||||
settings_fields(LBRY_SETTINGS_GROUP);
|
settings_fields(LBRY_SETTINGS_GROUP);
|
||||||
|
@ -17,7 +15,6 @@ $channel_list = $LBRY->daemon->channel_list();
|
||||||
submit_button('Save Settings');
|
submit_button('Save Settings');
|
||||||
?>
|
?>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h2>Your Publishable Channels</h2>
|
<h2>Your Publishable Channels</h2>
|
||||||
<?php if ($channel_list): ?>
|
<?php if ($channel_list): ?>
|
||||||
<ul class="lbry-channel-list">
|
<ul class="lbry-channel-list">
|
||||||
|
@ -28,7 +25,6 @@ $channel_list = $LBRY->daemon->channel_list();
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p>Looks like you haven't added any channels yet, feel free to do so below:</p>
|
<p>Looks like you haven't added any channels yet, feel free to do so below:</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<h2>Add a new channel to publish to:</h2>
|
<h2>Add a new channel to publish to:</h2>
|
||||||
<form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="post">
|
<form action="<?php echo esc_url(admin_url('admin-post.php')); ?>" method="post">
|
||||||
<?php wp_nonce_field('lbry_add_channel', '_lbrynonce'); ?>
|
<?php wp_nonce_field('lbry_add_channel', '_lbrynonce'); ?>
|
||||||
|
|
31
tests/bootstrap.php
Normal file
31
tests/bootstrap.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPUnit bootstrap file
|
||||||
|
*
|
||||||
|
* @package Lbrypress
|
||||||
|
*/
|
||||||
|
|
||||||
|
$_tests_dir = getenv( 'WP_TESTS_DIR' );
|
||||||
|
|
||||||
|
if ( ! $_tests_dir ) {
|
||||||
|
$_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! file_exists( $_tests_dir . '/includes/functions.php' ) ) {
|
||||||
|
echo "Could not find $_tests_dir/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; // WPCS: XSS ok.
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give access to tests_add_filter() function.
|
||||||
|
require_once $_tests_dir . '/includes/functions.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually load the plugin being tested.
|
||||||
|
*/
|
||||||
|
function _manually_load_plugin() {
|
||||||
|
require dirname( dirname( __FILE__ ) ) . '/lbrypress.php';
|
||||||
|
}
|
||||||
|
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
|
||||||
|
|
||||||
|
// Start up the WP testing environment.
|
||||||
|
require $_tests_dir . '/includes/bootstrap.php';
|
56
tests/convert_actual.md
Normal file
56
tests/convert_actual.md
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
Markdown Test!
|
||||||
|
==============
|
||||||
|
|
||||||
|
**([FAIR.org](https://fair.org/home/trump-admin-follows-corporate-media-playbook-for-war-with-iran/))** — Three years ago, as Americans debated the Joint Comprehensive Plan of Action (JCPOA) agreement with the Islamic Republic of Iran—popularly known as “the Iran deal”—I highlighted a troubling media trend on **FAIR.org** ([8/20/15](https://fair.org/home/giving-war-a-chance/)): “For nearly all commentators, regardless of their position, war is the only alternative to that position.”
|
||||||
|
|
||||||
|
In the months since US President Donald Trump tore up the JCPOA agreement, his administration has been trying to make good on corporate media’s collective prediction. Last week, John Bolton (**BBC**, [9/26/18](https://www.bbc.com/news/world-us-canada-45647863)), Trump’s national security advisor and chief warmonger, told Iran’s leaders and the world that there would be “hell to pay” if they dare to “cross us.”
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/BBC-John-Bolton-610x343.jpg)John Bolton (**BBC**, [9/26/18](https://www.bbc.com/news/world-us-canada-45647863)): “Let my message today be clear: We are watching, and we will come after you.”That Bolton’s bellicose statements do not send shockwaves of pure horror across a [debt-strapped](https://www.reuters.com/article/us-usa-economy-budget/u-s-government-posts-214-billion-deficit-in-august-idUSKCN1LT2XL) and [war-weary](https://nyti.ms/2N7cg3m) United States is thanks in large part to incessant priming for war, facilitated by corporate media across the entire political spectrum, with a particular focus on Iran.
|
||||||
|
|
||||||
|
Back in 2015, while current “resistance” stalwarts like the **Washington Post** ([4/2/15](https://www.washingtonpost.com/opinions/a-nuclear-deal-with-iran-is-the-best-option/2015/04/02/bc8292d2-d978-11e4-8103-fa84725dbf9d_story.html)) and **Politico** ([8/11/15](//www.politico.com/magazine/story/2015/08/iran-deal-rejection-121257.html)) warned us that war with Iran was the most likely alternative to the JCPOA, conservative standard-bearers such as **Fox News** ([7/14/15](//insider.foxnews.com/2015/07/14/dick-cheney-hannity-iran-nuke-deal-brings-world-closer-nuclear-war)) and the **Washington Times** ([8/10/15](//www.washingtontimes.com/news/2015/aug/10/ed-feulner-iran-nuclear-deal-makes-war-more-likely/)) foretold that war with Iran was the agreement’s most likely outcome. Three years hence, this dynamic has not changed.
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/NYT-Iran-Deal-War-610x411.jpg)Cartoonist Patrick Chappatte (**New York Times**, [5/10/18](https://nyti.ms/2I9LCnJ)) presents Trump and Bolton’s “deal” for Iran.To experience the full menu of US media’s single-mindedness about Iran, one need only buy a subscription to the **New York Times**. After Trump withdrew from the JCPOA, the **Times**’ editorial board ([5/8/18](https://nyti.ms/2HXldJD)) wrote that his move would “lay conditions for a possible wider war in the Middle East.” Susan Rice (**New York Times**, [5/8/18](https://nyti.ms/2FXt4kH)), President Barack Obama’s national security advisor, agreed: “We could face the choice of going to war or acquiescing to a nuclear-armed Iran,” she warned. Cartoonist Patrick Chappatte (**New York Times**, [5/10/18](https://nyti.ms/2I9LCnJ)) was characteristically more direct, penning an image of Trump alongside Bolton, holding a fictitious new agreement featuring the singular, ultimate word: “WAR.”
|
||||||
|
|
||||||
|
On the other hand, calling Trump’s turn against JCPOA a “courageous decision,” **Times** columnist Bret Stephens ([5/8/18](https://nyti.ms/2FWTz9O)) explained that the move was meant to force the Iranian government to make a choice: Either accede to US demands or “pursue their nuclear ambitions at the cost of economic ruin and possible war.” (Hardly courageous, when we all know there is no chance that Trump or Stephens would enlist should war materialize.)
|
||||||
|
|
||||||
|
Trump’s [latest antics](https://youtu.be/KfVdIKaQzW8) at the United Nations have spurred a wave of similar reaction across corporate media. Describing his threat to “totally destroy North Korea” at the UN General Assembly last year as “pointed and sharp,” **Fox News** anchor Eric Shawn ([9/23/18](https://video.foxnews.com/v/5838934710001/)) asked Bill Richardson, an Obama ally and President Bill Clinton’s ambassador to the UN, whether Trump would take the same approach toward Iran. “That aggressive policy we have with Iran is going to continue,” Richardson reassured the audience, “and I don’t think Iran is helping themselves.” In other words, if the United States starts a war with Iran, it’s totally Iran’s fault.
|
||||||
|
|
||||||
|
**Politico** ([9/23/18](https://www.politico.com/story/2018/09/23/trump-iran-war-foreign-policy-836411)), meanwhile, reported that Trump “is risking a potential war with Iran unless he engages the Islamist-led country using diplomacy.” In other words, if the United States starts a war with Iran, it’s totally Trump’s fault. Rice (**New York Times**, [9/26/18](https://nyti.ms/2N4AZjF)) reiterated her view that Trump’s rhetoric “presages the prospect of war in the Persian Gulf.” Whoever would be the responsible party is up for debate, but that war is in our future is apparently all but certain.
|
||||||
|
|
||||||
|
**Politico**’s article cited a [statement](https://s3-us-west-1.amazonaws.com/coalitionagainstirannukes/Statement_Sept18.pdf) signed by such esteemed US experts on war-making as Madeleine Albright, who presided over Clinton’s [inhuman sanctions](https://nyti.ms/2tvy0MU) against Iraq in the ’90s, and Ryan Crocker, former ambassador for presidents George W. Bush and Obama to some of America’s favorite killing fields: Iraq, Afghanistan, Pakistan and Syria. James Clapper, Obama’s National Intelligence Director, who also signed the letter, played an [important role](https://www.washingtontimes.com/news/2010/jun/4/likely-intel-chief-clapper-held-disputed-wmd-view/) in trumping up WMD evidence against Saddam Hussein before the United States invaded Iraq in 2003. When it comes to US aggression, they’re the experts.
|
||||||
|
|
||||||
|
**Vanity Fair** ([9/26/18](https://www.vanityfair.com/news/2018/09/john-bolton-iran-united-nations)) interviewed John Glaser of the Cato Institute, who called Trump’s strategy “pathetic,” and also warned that it forebodes war. In an effort to “one-up Obama,” Glaser explained, Trump’s plan is “to apply extreme economic pressure and explicit threats of war in order to get Iran to capitulate.” Sound familiar? As Glaser implies, this was [exactly Obama’s strategy](https://theintercept.com/2015/08/06/obama-summarizes-record/), only then it wasn’t seen as “pathetic,” but rather reasonable, and the sole means for preventing the war that every US pundit and politician saw around the corner (**The Hill**, [8/9/15](https://thehill.com/blogs/ballot-box/presidential-races/250683-sanders-war-the-alternative-if-iran-deal-fails)).
|
||||||
|
|
||||||
|
When everyone decides that war is the only other possibility, it starts to look like an inevitability. But even when they aren’t overtly stoking war fever against Iran, corporate media prime the militaristic pump in more subtle yet equally disturbing ways.
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/CNN-Netanyahu-610x343.jpg)Benjamin Netanyahu speaks for the Iranian people on **CNN** ([9/29/18](https://www.cnn.com/videos/world/2018/09/29/labott-netanyahu-iran-regime-intv-sot-vpx.cnn)).First among these is the near-complete erasure of Iranian voices from US airwaves (**FAIR.org**, [7/24/15](https://fair.org/home/side-by-side-coverage-of-cuba-and-iran-highlights-shift-in-us-media-villain-making/)). Rather than ask Iranians directly, national outlets like **CNN** ([9/29/18](https://www.cnn.com/videos/world/2018/09/29/labott-netanyahu-iran-regime-intv-sot-vpx.cnn)) prefer to invite the prime minister of Israel, [serial Iran alarmist](https://theintercept.com/2015/03/02/brief-history-netanyahu-crying-wolf-iranian-nuclear-bomb/) and regional pariah Benjamin Netanyahu, to speak for them. During a jovial discussion this weekend over whether regime change and/or economic collapse is Iran’s most likely fate, Netanyahu explained to the audience that, either way, “The ones who will be happiest if that happens are the people of Iran.” No people of Iran were on hand to confirm or deny this assessment.
|
||||||
|
|
||||||
|
**Bloomberg** ([9/30/18](https://www.bloomberg.com/view/articles/2018-09-30/what-s-not-to-like-about-trump-iran-oil-sanctions-100-oil)) similarly wanted to know, “What’s not to like about Trump’s Iran oil sanctions?” Julian Lee gleefully reported that “they are crippling exports from the Islamic Republic, at minimal cost to the US.” One might think the [toll sanctions take](https://www.aljazeera.com/news/2018/08/iran-doctors-sanctions-endangering-patients-lives-180830064012071.html) on innocent Iranians would be something not to like, but **Bloomberg** merely worried that, notwithstanding the windfall for US refineries, “oil at $100 a barrel would be bad news for drivers everywhere—including those in the US.”
|
||||||
|
|
||||||
|
Another prized tactic is to [whitewash Saudi Arabia](https://www.counterpunch.org/2018/03/05/the-1-5-billion-campaign-to-whitewash-genocide-in-yemen/), Iran’s chief geopolitical rival, whose genocidal destruction of Yemen is made possible by the United States, about which corporate media remain overwhelmingly silent (**FAIR.org**,[ 7/23/18](https://fair.org/home/action-alert-its-been-over-a-year-since-msnbc-has-mentioned-us-war-in-yemen/)). Iran’s involvement in Yemen, which both Trump and the **New York Times** ([9/12/18](https://nyti.ms/2MqieXJ)) describe as “malign behavior,” is a principal justification for US support of Saudi Arabia, including the[ US-supplied bombs](https://www.cnn.com/2018/08/17/middleeast/us-saudi-yemen-bus-strike-intl/index.html) that recently ended the brief lives of over 40 Yemeni schoolchildren. Lockheed Martin’s stock is [up 34 percent](https://www.marketwatch.com/investing/stock/LMT/historical?siteid=mktw&date=01%2F20%2F2017)from Trump’s inauguration day.
|
||||||
|
|
||||||
|
Corporate media go beyond a simple coverup of Saudi crimes to evangelize their leadership as the liberal antidote to Iran’s “theocracy.” Who can forget Thomas Friedman’s revolting puff piece for the Saudi crown prince Mohammad bin Salman? Extensively quoting Salman (**New York Times**, [11/23/17](https://nyti.ms/2i0mwfg)), who refers to Iranian Ayatollah Ali Khamenei as “the new Hitler of the Middle East,” Friedman nevertheless remains pessimistic about whether “MBS and his team” can see their stand against Iran through, as “dysfunction and rivalries within the Sunni Arab world generally have prevented forming a unified front.” Oh well, every team needs cheerleaders, and Friedman isn’t just a fair-weather fan.
|
||||||
|
|
||||||
|
While Friedman (**New York Times**, [5/15/18](https://nyti.ms/2GmBgLo)) believes that Trump has drawn “some needed attention to Iran’s bad behavior,” for him pivotal questions remain unanswered, such as “who is going to take over in Tehran if the current Islamic regime collapses?” One immediate fix he proposed was to censure Iran’s metaphorical “occupation” of Syria, Iraq and Lebanon. Isn’t this ironic coming from an unapologetic propagandist for Washington’s decades-long, non-metaphorical occupation of the two countries to the east and west of Iran (**FAIR.org**, [12/9/15](https://fair.org/home/friedman-goes-after-trump-hey-massive-bombing-was-my-idea/))?
|
||||||
|
|
||||||
|
In a surprising break from corporate media convention, **USA Today** ([9/26/18](https://www.usatoday.com/story/opinion/voices/2018/09/26/iran-united-states-foreign-policy-iraq-war-column/1379872002/)) published a column on US/Iran relations written by an actual Iranian. Reflecting on the [CIA-orchestrated coup](https://en.wikipedia.org/wiki/1953_Iranian_coup_d%27%C3%A9tat) against Iran’s elected government in 1953, Azadeh Shahshahani, who was born four days after the 1979 revolution there, wrote:
|
||||||
|
|
||||||
|
> “I often wonder what would have happened if that coup had not worked, if \[Prime Minister\] Mosaddeq had been allowed to govern, if democracy had been allowed to flourish.”
|
||||||
|
|
||||||
|
“It is time for the US government to stop intervening in Iran and let the Iranian people determine their own destiny,” she beseeched readers.
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/Real-News-Code-Pink-610x343.png)Code Pink’s Medea Benjamin confronts the head of Trump’s “Iran Action Group” (**Real News**, [9/21/18](https://youtu.be/peJGmeg6ZE8)).Shahshahani’s call is supported by some who have rejected corporate media’s war propaganda and have gone to extreme lengths to have their perspectives heard. Anti-war activist and Code Pink founder Medea Benjamin was recently forcibly removed after she upstaged Brian Hook, leader of Trump’s Iran Action Group, on live TV, calling his press conference “the most ridiculous thing I have ever seen” (**Real News**, [9/21/18](https://youtu.be/peJGmeg6ZE8)). Benjamin implored the audience: “Let’s talk about Saudi Arabia. Is that who our allies are?”
|
||||||
|
|
||||||
|
“How dare you bring up the issue of Yemen,” admonished Benjamin as she was dragged from the room. “It’s the Saudi bombing that is killing most people in Yemen. So let’s get real. No more war! Peace with Iran!” Code Pink is [currently petitioning](https://www.codepink.org/dont_iraq_iran?utm_campaign=iran_national_sept25) the **New York Times** and **Washington Post** to stop propagandizing war.
|
||||||
|
|
||||||
|
Sadly, no matter whom you ask in corporate media, be they spokespeople for “Trump’s America” or “the resistance,” peace remains an elusive choice in the US political imagination. And while the public was focused last week on Supreme Court nominee [Brett Kavanaugh’s ](https://youtu.be/7zVOkb3CdZ0)[perjurious testimony](https://www.currentaffairs.org/2018/09/how-we-know-kavanaugh-is-lying), the Senate finalized a[$674 billion “defense” budget](https://www.democracynow.org/2018/9/20/headlines/senate_passes_674_billion_military_spending_bill). Every single Democrat in the chamber voted in favor of the bill, [explicitly naming Iran](https://www.congress.gov/bill/115th-congress/house-bill/6157/text) as persona non grata in the United States’[world-leading arms supply network](https://www.sipri.org/news/press-release/2018/asia-and-middle-east-lead-rising-trend-arms-imports-us-exports-grow-significantly-says-sipri), which has seen a 25 percent increase in exports since Obama took office in 2009.
|
||||||
|
|
||||||
|
The US government’s imperial ambitions are perhaps its only truly bipartisan project—what the **New York Times** euphemistically refers to as “globalism.” Nowhere was this on fuller display than at the funeral for Republican Sen. John McCain (**FAIR.org**,[ 9/11/18](https://fair.org/home/maverick-media-use-mccain-funeral-to-shore-up-us-imperialism/)), where politicians of all stripes were tripping over themselves to produce the best accolades for a man who [infamously sang](https://youtu.be/o-zoPgv_nYg)“bomb bomb bomb, bomb bomb Iran” to the tune of a Beach Boys song.
|
||||||
|
|
||||||
|
McCain’s bloodlust was nothing new. Nearly a hundred years ago, after the West’s imperial competition culminated in the most destructive war the world had ever seen, the brilliant American sociologist and anti-colonial author WEB Du Bois [wrote](https://www.gutenberg.org/files/15210/15210-h/15210-h.htm), “This is not Europe gone mad; this is not aberration nor insanity; this *is* Europe.”
|
||||||
|
|
||||||
|
Iranian leaders have repeatedly said they do not want war with the US (**AP**, [9/27/18](https://apnews.com/1cb23ee1641041c5910595715f2ea334)), but US corporate media, despite frequently characterizing Trump as a “mad king” (**FAIR.org**, [6/13/18](https://fair.org/home/why-do-us-media-only-worry-about-one-authoritarians-nukes/)), continue to play an instrumental role in rationalizing a future war with Iran. Should such an intentional catastrophe come to pass, we can hardly say that this would be America gone mad; war is not aberration, it is always presented as the next sane choice. This *is* America.
|
||||||
|
|
||||||
|
*By [John C. O’Day](https://fair.org/author/john-c-oday/) / Republished with permission / [FAIR.org](https://fair.org/) / [Report a typo](mailto:edits@theantimedia.org)*
|
||||||
|
|
||||||
|
*This article was chosen for republication based on the interest of our readers. Anti-Media republishes stories from a number of other independent news sources. The views expressed in this article are the author’s own and do not reflect Anti-Media editorial policy.*
|
33
tests/convert_content.txt
Normal file
33
tests/convert_content.txt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<p><strong>(<a href="https://fair.org/home/trump-admin-follows-corporate-media-playbook-for-war-with-iran/" target="_blank" rel="noopener">FAIR.org</a>) </strong><span style="font-weight: 400">— </span>Three years ago, as Americans debated the Joint Comprehensive Plan of Action (JCPOA) agreement with the Islamic Republic of Iran—popularly known as “the Iran deal”—I highlighted a troubling media trend on <b>FAIR.org</b> (<a href="https://fair.org/home/giving-war-a-chance/">8/20/15</a>): “For nearly all commentators, regardless of their position, war is the only alternative to that position.”</p>
|
||||||
|
<p>In the months since US President Donald Trump tore up the JCPOA agreement, his administration has been trying to make good on corporate media’s collective prediction. Last week, John Bolton (<b>BBC</b>, <a href="https://www.bbc.com/news/world-us-canada-45647863">9/26/18</a>), Trump’s national security advisor and chief warmonger, told Iran’s leaders and the world that there would be “hell to pay” if they dare to “cross us.”</p>
|
||||||
|
<figure id="attachment_170151" style="width: 610px" class="wp-caption alignnone"><img class="size-full wp-image-170151" src="https://theantimedia.com/wp-content/uploads/2018/10/BBC-John-Bolton-610x343.jpg" alt="" width="610" height="343" /><figcaption class="wp-caption-text">John Bolton (<strong>BBC</strong>, <a href="https://www.bbc.com/news/world-us-canada-45647863">9/26/18</a>): “Let my message today be clear: We are watching, and we will come after you.”</figcaption></figure>
|
||||||
|
<p>That Bolton’s bellicose statements do not send shockwaves of pure horror across a <a href="https://www.reuters.com/article/us-usa-economy-budget/u-s-government-posts-214-billion-deficit-in-august-idUSKCN1LT2XL">debt-strapped</a> and <a href="https://nyti.ms/2N7cg3m">war-weary</a> United States is thanks in large part to incessant priming for war, facilitated by corporate media across the entire political spectrum, with a particular focus on Iran.</p>
|
||||||
|
<p>Back in 2015, while current “resistance” stalwarts like the <b>Washington Post </b>(<a href="https://www.washingtonpost.com/opinions/a-nuclear-deal-with-iran-is-the-best-option/2015/04/02/bc8292d2-d978-11e4-8103-fa84725dbf9d_story.html">4/2/15</a>) and <b>Politico</b> (<a href="//www.politico.com/magazine/story/2015/08/iran-deal-rejection-121257.html">8/11/15</a>) warned us that war with Iran was the most likely alternative to the JCPOA, conservative standard-bearers such as <b>Fox News </b>(<a href="//insider.foxnews.com/2015/07/14/dick-cheney-hannity-iran-nuke-deal-brings-world-closer-nuclear-war">7/14/15</a>) and the <b>Washington Times</b> (<a href="//www.washingtontimes.com/news/2015/aug/10/ed-feulner-iran-nuclear-deal-makes-war-more-likely/">8/10/15</a>) foretold that war with Iran was the agreement’s most likely outcome. Three years hence, this dynamic has not changed.</p>
|
||||||
|
<figure id="attachment_170150" style="width: 610px" class="wp-caption alignnone"><img class="size-full wp-image-170150" src="https://theantimedia.com/wp-content/uploads/2018/10/NYT-Iran-Deal-War-610x411.jpg" alt="" width="610" height="411" /><figcaption class="wp-caption-text">Cartoonist Patrick Chappatte (<strong>New York Times</strong>, <a href="https://nyti.ms/2I9LCnJ">5/10/18</a>) presents Trump and Bolton’s “deal” for Iran.</figcaption></figure>
|
||||||
|
<p>To experience the full menu of US media’s single-mindedness about Iran, one need only buy a subscription to the <b>New York Times</b>. After Trump withdrew from the JCPOA, the <b>Times</b>’ editorial board (<a href="https://nyti.ms/2HXldJD">5/8/18</a>) wrote that his move would “lay conditions for a possible wider war in the Middle East.” Susan Rice (<b>New York Times</b>, <a href="https://nyti.ms/2FXt4kH">5/8/18</a>), President Barack Obama’s national security advisor, agreed: “We could face the choice of going to war or acquiescing to a nuclear-armed Iran,” she warned. Cartoonist Patrick Chappatte (<b>New York Times</b>, <a href="https://nyti.ms/2I9LCnJ">5/10/18</a>) was characteristically more direct, penning an image of Trump alongside Bolton, holding a fictitious new agreement featuring the singular, ultimate word: “WAR.”</p>
|
||||||
|
<p>On the other hand, calling Trump’s turn against JCPOA a “courageous decision,” <b>Times</b> columnist Bret Stephens (<a href="https://nyti.ms/2FWTz9O">5/8/18</a>) explained that the move was meant to force the Iranian government to make a choice: Either accede to US demands or “pursue their nuclear ambitions at the cost of economic ruin and possible war.” (Hardly courageous, when we all know there is no chance that Trump or Stephens would enlist should war materialize.)</p>
|
||||||
|
<p>Trump’s <a href="https://youtu.be/KfVdIKaQzW8">latest antics</a> at the United Nations have spurred a wave of similar reaction across corporate media. Describing his threat to “totally destroy North Korea” at the UN General Assembly last year as “pointed and sharp,” <b>Fox News </b>anchor Eric Shawn (<a href="https://video.foxnews.com/v/5838934710001/">9/23/18</a>) asked Bill Richardson, an Obama ally and President Bill Clinton’s ambassador to the UN, whether Trump would take the same approach toward Iran. “That aggressive policy we have with Iran is going to continue,” Richardson reassured the audience, “and I don’t think Iran is helping themselves.” In other words, if the United States starts a war with Iran, it’s totally Iran’s fault.</p>
|
||||||
|
<p><b>Politico</b> (<a href="https://www.politico.com/story/2018/09/23/trump-iran-war-foreign-policy-836411">9/23/18</a>), meanwhile, reported that Trump “is risking a potential war with Iran unless he engages the Islamist-led country using diplomacy.” In other words, if the United States starts a war with Iran, it’s totally Trump’s fault. Rice (<b>New York Times</b>, <a href="https://nyti.ms/2N4AZjF">9/26/18</a>) reiterated her view that Trump’s rhetoric “presages the prospect of war in the Persian Gulf.” Whoever would be the responsible party is up for debate, but that war is in our future is apparently all but certain.</p>
|
||||||
|
<p><b>Politico</b>’s article cited a <a href="https://s3-us-west-1.amazonaws.com/coalitionagainstirannukes/Statement_Sept18.pdf">statement</a> signed by such esteemed US experts on war-making as Madeleine Albright, who presided over Clinton’s <a href="https://nyti.ms/2tvy0MU">inhuman sanctions</a> against Iraq in the ’90s, and Ryan Crocker, former ambassador for presidents George W. Bush and Obama to some of America’s favorite killing fields: Iraq, Afghanistan, Pakistan and Syria. James Clapper, Obama’s National Intelligence Director, who also signed the letter, played an <a href="https://www.washingtontimes.com/news/2010/jun/4/likely-intel-chief-clapper-held-disputed-wmd-view/">important role</a> in trumping up WMD evidence against Saddam Hussein before the United States invaded Iraq in 2003. When it comes to US aggression, they’re the experts.</p>
|
||||||
|
<p><b>Vanity Fair</b> (<a href="https://www.vanityfair.com/news/2018/09/john-bolton-iran-united-nations">9/26/18</a>) interviewed John Glaser of the Cato Institute, who called Trump’s strategy “pathetic,” and also warned that it forebodes war. In an effort to “one-up Obama,” Glaser explained, Trump’s plan is “to apply extreme economic pressure and explicit threats of war in order to get Iran to capitulate.” Sound familiar? As Glaser implies, this was <a href="https://theintercept.com/2015/08/06/obama-summarizes-record/">exactly Obama’s strategy</a>, only then it wasn’t seen as “pathetic,” but rather reasonable, and the sole means for preventing the war that every US pundit and politician saw around the corner (<b>The Hill</b>, <a href="https://thehill.com/blogs/ballot-box/presidential-races/250683-sanders-war-the-alternative-if-iran-deal-fails">8/9/15</a>).</p>
|
||||||
|
<p>When everyone decides that war is the only other possibility, it starts to look like an inevitability. But even when they aren’t overtly stoking war fever against Iran, corporate media prime the militaristic pump in more subtle yet equally disturbing ways.</p>
|
||||||
|
<figure id="attachment_170149" style="width: 610px" class="wp-caption alignnone"><img class="size-full wp-image-170149" src="https://theantimedia.com/wp-content/uploads/2018/10/CNN-Netanyahu-610x343.jpg" alt="" width="610" height="343" /><figcaption class="wp-caption-text">Benjamin Netanyahu speaks for the Iranian people on <strong>CNN</strong> (<a href="https://www.cnn.com/videos/world/2018/09/29/labott-netanyahu-iran-regime-intv-sot-vpx.cnn">9/29/18</a>).</figcaption></figure>
|
||||||
|
<p>First among these is the near-complete erasure of Iranian voices from US airwaves (<b>FAIR.org</b>, <a href="https://fair.org/home/side-by-side-coverage-of-cuba-and-iran-highlights-shift-in-us-media-villain-making/">7/24/15</a>). Rather than ask Iranians directly, national outlets like <b>CNN</b> (<a href="https://www.cnn.com/videos/world/2018/09/29/labott-netanyahu-iran-regime-intv-sot-vpx.cnn">9/29/18</a>) prefer to invite the prime minister of Israel, <a href="https://theintercept.com/2015/03/02/brief-history-netanyahu-crying-wolf-iranian-nuclear-bomb/">serial Iran alarmist</a> and regional pariah Benjamin Netanyahu, to speak for them. During a jovial discussion this weekend over whether regime change and/or economic collapse is Iran’s most likely fate, Netanyahu explained to the audience that, either way, “The ones who will be happiest if that happens are the people of Iran.” No people of Iran were on hand to confirm or deny this assessment.</p>
|
||||||
|
<p><b>Bloomberg</b> (<a href="https://www.bloomberg.com/view/articles/2018-09-30/what-s-not-to-like-about-trump-iran-oil-sanctions-100-oil">9/30/18</a>) similarly wanted to know, “What’s not to like about Trump’s Iran oil sanctions?” Julian Lee gleefully reported that “they are crippling exports from the Islamic Republic, at minimal cost to the US.” One might think the <a href="https://www.aljazeera.com/news/2018/08/iran-doctors-sanctions-endangering-patients-lives-180830064012071.html">toll sanctions take</a> on innocent Iranians would be something not to like, but <b>Bloomberg</b> merely worried that, notwithstanding the windfall for US refineries, “oil at $100 a barrel would be bad news for drivers everywhere—including those in the US.”</p>
|
||||||
|
<p>Another prized tactic is to <a href="https://www.counterpunch.org/2018/03/05/the-1-5-billion-campaign-to-whitewash-genocide-in-yemen/">whitewash Saudi Arabia</a>, Iran’s chief geopolitical rival, whose genocidal destruction of Yemen is made possible by the United States, about which corporate media remain overwhelmingly silent (<b>FAIR.org</b>,<a href="https://fair.org/home/action-alert-its-been-over-a-year-since-msnbc-has-mentioned-us-war-in-yemen/"> 7/23/18</a>). Iran’s involvement in Yemen, which both Trump and the<b> New York Times </b>(<a href="https://nyti.ms/2MqieXJ">9/12/18</a>) describe as “malign behavior,” is a principal justification for US support of Saudi Arabia, including the<a href="https://www.cnn.com/2018/08/17/middleeast/us-saudi-yemen-bus-strike-intl/index.html"> US-supplied bombs</a> that recently ended the brief lives of over 40 Yemeni schoolchildren. Lockheed Martin’s stock is <a href="https://www.marketwatch.com/investing/stock/LMT/historical?siteid=mktw&date=01%2F20%2F2017">up 34 percent</a>from Trump’s inauguration day.</p>
|
||||||
|
<p>Corporate media go beyond a simple coverup of Saudi crimes to evangelize their leadership as the liberal antidote to Iran’s “theocracy.” Who can forget Thomas Friedman’s revolting puff piece for the Saudi crown prince Mohammad bin Salman? Extensively quoting Salman (<b>New York Times</b>, <a href="https://nyti.ms/2i0mwfg">11/23/17</a>), who refers to Iranian Ayatollah Ali Khamenei as “the new Hitler of the Middle East,” Friedman nevertheless remains pessimistic about whether “MBS and his team” can see their stand against Iran through, as “dysfunction and rivalries within the Sunni Arab world generally have prevented forming a unified front.” Oh well, every team needs cheerleaders, and Friedman isn’t just a fair-weather fan.</p>
|
||||||
|
<p>While Friedman (<b>New York Times</b>, <a href="https://nyti.ms/2GmBgLo">5/15/18</a>) believes that Trump has drawn “some needed attention to Iran’s bad behavior,” for him pivotal questions remain unanswered, such as “who is going to take over in Tehran if the current Islamic regime collapses?” One immediate fix he proposed was to censure Iran’s metaphorical “occupation” of Syria, Iraq and Lebanon. Isn’t this ironic coming from an unapologetic propagandist for Washington’s decades-long, non-metaphorical occupation of the two countries to the east and west of Iran (<b>FAIR.org</b>, <a href="https://fair.org/home/friedman-goes-after-trump-hey-massive-bombing-was-my-idea/">12/9/15</a>)?</p>
|
||||||
|
<p>In a surprising break from corporate media convention, <b>USA Today</b> (<a href="https://www.usatoday.com/story/opinion/voices/2018/09/26/iran-united-states-foreign-policy-iraq-war-column/1379872002/">9/26/18</a>) published a column on US/Iran relations written by an actual Iranian. Reflecting on the <a href="https://en.wikipedia.org/wiki/1953_Iranian_coup_d%27%C3%A9tat">CIA-orchestrated coup</a> against Iran’s elected government in 1953, Azadeh Shahshahani, who was born four days after the 1979 revolution there, wrote:</p>
|
||||||
|
<blockquote>
|
||||||
|
<p>“I often wonder what would have happened if that coup had not worked, if [Prime Minister] Mosaddeq had been allowed to govern, if democracy had been allowed to flourish.”</p>
|
||||||
|
</blockquote>
|
||||||
|
<p>“It is time for the US government to stop intervening in Iran and let the Iranian people determine their own destiny,” she beseeched readers.</p>
|
||||||
|
<figure id="attachment_170148" style="width: 610px" class="wp-caption alignnone"><img class="size-full wp-image-170148" src="https://theantimedia.com/wp-content/uploads/2018/10/Real-News-Code-Pink-610x343.png" alt="" width="610" height="343" /><figcaption class="wp-caption-text">Code Pink’s Medea Benjamin confronts the head of Trump’s “Iran Action Group” (<strong>Real News</strong>, <a href="https://youtu.be/peJGmeg6ZE8">9/21/18</a>).</figcaption></figure>
|
||||||
|
<p>Shahshahani’s call is supported by some who have rejected corporate media’s war propaganda and have gone to extreme lengths to have their perspectives heard. Anti-war activist and Code Pink founder Medea Benjamin was recently forcibly removed after she upstaged Brian Hook, leader of Trump’s Iran Action Group, on live TV, calling his press conference “the most ridiculous thing I have ever seen” (<b>Real News</b>, <a href="https://youtu.be/peJGmeg6ZE8">9/21/18</a>). Benjamin implored the audience: “Let’s talk about Saudi Arabia. Is that who our allies are?”</p>
|
||||||
|
<p>“How dare you bring up the issue of Yemen,” admonished Benjamin as she was dragged from the room. “It’s the Saudi bombing that is killing most people in Yemen. So let’s get real. No more war! Peace with Iran!” Code Pink is <a href="https://www.codepink.org/dont_iraq_iran?utm_campaign=iran_national_sept25">currently petitioning</a> the <b>New York Times</b> and <b>Washington Post</b> to stop propagandizing war.</p>
|
||||||
|
<p>Sadly, no matter whom you ask in corporate media, be they spokespeople for “Trump’s America” or “the resistance,” peace remains an elusive choice in the US political imagination. And while the public was focused last week on Supreme Court nominee <a href="https://youtu.be/7zVOkb3CdZ0">Brett Kavanaugh’s </a><a href="https://www.currentaffairs.org/2018/09/how-we-know-kavanaugh-is-lying">perjurious testimony</a>, the Senate finalized a<a href="https://www.democracynow.org/2018/9/20/headlines/senate_passes_674_billion_military_spending_bill">$674 billion “defense” budget</a>. Every single Democrat in the chamber voted in favor of the bill, <a href="https://www.congress.gov/bill/115th-congress/house-bill/6157/text">explicitly naming Iran</a> as persona non grata in the United States’<a href="https://www.sipri.org/news/press-release/2018/asia-and-middle-east-lead-rising-trend-arms-imports-us-exports-grow-significantly-says-sipri">world-leading arms supply network</a>, which has seen a 25 percent increase in exports since Obama took office in 2009.</p>
|
||||||
|
<p>The US government’s imperial ambitions are perhaps its only truly bipartisan project—what the <b>New York Times</b> euphemistically refers to as “globalism.” Nowhere was this on fuller display than at the funeral for Republican Sen. John McCain (<b>FAIR.org</b>,<a href="https://fair.org/home/maverick-media-use-mccain-funeral-to-shore-up-us-imperialism/"> 9/11/18</a>), where politicians of all stripes were tripping over themselves to produce the best accolades for a man who <a href="https://youtu.be/o-zoPgv_nYg">infamously sang</a>“bomb bomb bomb, bomb bomb Iran” to the tune of a Beach Boys song.</p>
|
||||||
|
<p>McCain’s bloodlust was nothing new. Nearly a hundred years ago, after the West’s imperial competition culminated in the most destructive war the world had ever seen, the brilliant American sociologist and anti-colonial author WEB Du Bois <a href="https://www.gutenberg.org/files/15210/15210-h/15210-h.htm">wrote</a>, “This is not Europe gone mad; this is not aberration nor insanity; this <i>is</i> Europe.”</p>
|
||||||
|
<p>Iranian leaders have repeatedly said they do not want war with the US (<b>AP</b>, <a href="https://apnews.com/1cb23ee1641041c5910595715f2ea334">9/27/18</a>), but US corporate media, despite frequently characterizing Trump as a “mad king” (<b>FAIR.org</b>, <a href="https://fair.org/home/why-do-us-media-only-worry-about-one-authoritarians-nukes/">6/13/18</a>), continue to play an instrumental role in rationalizing a future war with Iran. Should such an intentional catastrophe come to pass, we can hardly say that this would be America gone mad; war is not aberration, it is always presented as the next sane choice. This <i>is </i>America.</p>
|
||||||
|
<p style="text-align: center"><em>By <a href="https://fair.org/author/john-c-oday/">John C. O’Day</a> / Republished with permission / <a href="https://fair.org/">FAIR.org</a> / <a href="mailto:edits@theantimedia.org">Report a typo</a></em></p>
|
||||||
|
<p style="text-align: center"><em>This article was chosen for republication based on the interest of our readers. Anti-Media republishes stories from a number of other independent news sources. The views expressed in this article are the author’s own and do not reflect Anti-Media editorial policy.</em></p>
|
56
tests/convert_expected.md
Normal file
56
tests/convert_expected.md
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
Markdown Test!
|
||||||
|
==============
|
||||||
|
|
||||||
|
**([FAIR.org](https://fair.org/home/trump-admin-follows-corporate-media-playbook-for-war-with-iran/))** — Three years ago, as Americans debated the Joint Comprehensive Plan of Action (JCPOA) agreement with the Islamic Republic of Iran—popularly known as “the Iran deal”—I highlighted a troubling media trend on **FAIR.org** ([8/20/15](https://fair.org/home/giving-war-a-chance/)): “For nearly all commentators, regardless of their position, war is the only alternative to that position.”
|
||||||
|
|
||||||
|
In the months since US President Donald Trump tore up the JCPOA agreement, his administration has been trying to make good on corporate media’s collective prediction. Last week, John Bolton (**BBC**, [9/26/18](https://www.bbc.com/news/world-us-canada-45647863)), Trump’s national security advisor and chief warmonger, told Iran’s leaders and the world that there would be “hell to pay” if they dare to “cross us.”
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/BBC-John-Bolton-610x343.jpg)John Bolton (**BBC**, [9/26/18](https://www.bbc.com/news/world-us-canada-45647863)): “Let my message today be clear: We are watching, and we will come after you.”That Bolton’s bellicose statements do not send shockwaves of pure horror across a [debt-strapped](https://www.reuters.com/article/us-usa-economy-budget/u-s-government-posts-214-billion-deficit-in-august-idUSKCN1LT2XL) and [war-weary](https://nyti.ms/2N7cg3m) United States is thanks in large part to incessant priming for war, facilitated by corporate media across the entire political spectrum, with a particular focus on Iran.
|
||||||
|
|
||||||
|
Back in 2015, while current “resistance” stalwarts like the **Washington Post** ([4/2/15](https://www.washingtonpost.com/opinions/a-nuclear-deal-with-iran-is-the-best-option/2015/04/02/bc8292d2-d978-11e4-8103-fa84725dbf9d_story.html)) and **Politico** ([8/11/15](//www.politico.com/magazine/story/2015/08/iran-deal-rejection-121257.html)) warned us that war with Iran was the most likely alternative to the JCPOA, conservative standard-bearers such as **Fox News** ([7/14/15](//insider.foxnews.com/2015/07/14/dick-cheney-hannity-iran-nuke-deal-brings-world-closer-nuclear-war)) and the **Washington Times** ([8/10/15](//www.washingtontimes.com/news/2015/aug/10/ed-feulner-iran-nuclear-deal-makes-war-more-likely/)) foretold that war with Iran was the agreement’s most likely outcome. Three years hence, this dynamic has not changed.
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/NYT-Iran-Deal-War-610x411.jpg)Cartoonist Patrick Chappatte (**New York Times**, [5/10/18](https://nyti.ms/2I9LCnJ)) presents Trump and Bolton’s “deal” for Iran.To experience the full menu of US media’s single-mindedness about Iran, one need only buy a subscription to the **New York Times**. After Trump withdrew from the JCPOA, the **Times**’ editorial board ([5/8/18](https://nyti.ms/2HXldJD)) wrote that his move would “lay conditions for a possible wider war in the Middle East.” Susan Rice (**New York Times**, [5/8/18](https://nyti.ms/2FXt4kH)), President Barack Obama’s national security advisor, agreed: “We could face the choice of going to war or acquiescing to a nuclear-armed Iran,” she warned. Cartoonist Patrick Chappatte (**New York Times**, [5/10/18](https://nyti.ms/2I9LCnJ)) was characteristically more direct, penning an image of Trump alongside Bolton, holding a fictitious new agreement featuring the singular, ultimate word: “WAR.”
|
||||||
|
|
||||||
|
On the other hand, calling Trump’s turn against JCPOA a “courageous decision,” **Times** columnist Bret Stephens ([5/8/18](https://nyti.ms/2FWTz9O)) explained that the move was meant to force the Iranian government to make a choice: Either accede to US demands or “pursue their nuclear ambitions at the cost of economic ruin and possible war.” (Hardly courageous, when we all know there is no chance that Trump or Stephens would enlist should war materialize.)
|
||||||
|
|
||||||
|
Trump’s [latest antics](https://youtu.be/KfVdIKaQzW8) at the United Nations have spurred a wave of similar reaction across corporate media. Describing his threat to “totally destroy North Korea” at the UN General Assembly last year as “pointed and sharp,” **Fox News** anchor Eric Shawn ([9/23/18](https://video.foxnews.com/v/5838934710001/)) asked Bill Richardson, an Obama ally and President Bill Clinton’s ambassador to the UN, whether Trump would take the same approach toward Iran. “That aggressive policy we have with Iran is going to continue,” Richardson reassured the audience, “and I don’t think Iran is helping themselves.” In other words, if the United States starts a war with Iran, it’s totally Iran’s fault.
|
||||||
|
|
||||||
|
**Politico** ([9/23/18](https://www.politico.com/story/2018/09/23/trump-iran-war-foreign-policy-836411)), meanwhile, reported that Trump “is risking a potential war with Iran unless he engages the Islamist-led country using diplomacy.” In other words, if the United States starts a war with Iran, it’s totally Trump’s fault. Rice (**New York Times**, [9/26/18](https://nyti.ms/2N4AZjF)) reiterated her view that Trump’s rhetoric “presages the prospect of war in the Persian Gulf.” Whoever would be the responsible party is up for debate, but that war is in our future is apparently all but certain.
|
||||||
|
|
||||||
|
**Politico**’s article cited a [statement](https://s3-us-west-1.amazonaws.com/coalitionagainstirannukes/Statement_Sept18.pdf) signed by such esteemed US experts on war-making as Madeleine Albright, who presided over Clinton’s [inhuman sanctions](https://nyti.ms/2tvy0MU) against Iraq in the ’90s, and Ryan Crocker, former ambassador for presidents George W. Bush and Obama to some of America’s favorite killing fields: Iraq, Afghanistan, Pakistan and Syria. James Clapper, Obama’s National Intelligence Director, who also signed the letter, played an [important role](https://www.washingtontimes.com/news/2010/jun/4/likely-intel-chief-clapper-held-disputed-wmd-view/) in trumping up WMD evidence against Saddam Hussein before the United States invaded Iraq in 2003. When it comes to US aggression, they’re the experts.
|
||||||
|
|
||||||
|
**Vanity Fair** ([9/26/18](https://www.vanityfair.com/news/2018/09/john-bolton-iran-united-nations)) interviewed John Glaser of the Cato Institute, who called Trump’s strategy “pathetic,” and also warned that it forebodes war. In an effort to “one-up Obama,” Glaser explained, Trump’s plan is “to apply extreme economic pressure and explicit threats of war in order to get Iran to capitulate.” Sound familiar? As Glaser implies, this was [exactly Obama’s strategy](https://theintercept.com/2015/08/06/obama-summarizes-record/), only then it wasn’t seen as “pathetic,” but rather reasonable, and the sole means for preventing the war that every US pundit and politician saw around the corner (**The Hill**, [8/9/15](https://thehill.com/blogs/ballot-box/presidential-races/250683-sanders-war-the-alternative-if-iran-deal-fails)).
|
||||||
|
|
||||||
|
When everyone decides that war is the only other possibility, it starts to look like an inevitability. But even when they aren’t overtly stoking war fever against Iran, corporate media prime the militaristic pump in more subtle yet equally disturbing ways.
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/CNN-Netanyahu-610x343.jpg)Benjamin Netanyahu speaks for the Iranian people on **CNN** ([9/29/18](https://www.cnn.com/videos/world/2018/09/29/labott-netanyahu-iran-regime-intv-sot-vpx.cnn)).First among these is the near-complete erasure of Iranian voices from US airwaves (**FAIR.org**, [7/24/15](https://fair.org/home/side-by-side-coverage-of-cuba-and-iran-highlights-shift-in-us-media-villain-making/)). Rather than ask Iranians directly, national outlets like **CNN** ([9/29/18](https://www.cnn.com/videos/world/2018/09/29/labott-netanyahu-iran-regime-intv-sot-vpx.cnn)) prefer to invite the prime minister of Israel, [serial Iran alarmist](https://theintercept.com/2015/03/02/brief-history-netanyahu-crying-wolf-iranian-nuclear-bomb/) and regional pariah Benjamin Netanyahu, to speak for them. During a jovial discussion this weekend over whether regime change and/or economic collapse is Iran’s most likely fate, Netanyahu explained to the audience that, either way, “The ones who will be happiest if that happens are the people of Iran.” No people of Iran were on hand to confirm or deny this assessment.
|
||||||
|
|
||||||
|
**Bloomberg** ([9/30/18](https://www.bloomberg.com/view/articles/2018-09-30/what-s-not-to-like-about-trump-iran-oil-sanctions-100-oil)) similarly wanted to know, “What’s not to like about Trump’s Iran oil sanctions?” Julian Lee gleefully reported that “they are crippling exports from the Islamic Republic, at minimal cost to the US.” One might think the [toll sanctions take](https://www.aljazeera.com/news/2018/08/iran-doctors-sanctions-endangering-patients-lives-180830064012071.html) on innocent Iranians would be something not to like, but **Bloomberg** merely worried that, notwithstanding the windfall for US refineries, “oil at $100 a barrel would be bad news for drivers everywhere—including those in the US.”
|
||||||
|
|
||||||
|
Another prized tactic is to [whitewash Saudi Arabia](https://www.counterpunch.org/2018/03/05/the-1-5-billion-campaign-to-whitewash-genocide-in-yemen/), Iran’s chief geopolitical rival, whose genocidal destruction of Yemen is made possible by the United States, about which corporate media remain overwhelmingly silent (**FAIR.org**,[ 7/23/18](https://fair.org/home/action-alert-its-been-over-a-year-since-msnbc-has-mentioned-us-war-in-yemen/)). Iran’s involvement in Yemen, which both Trump and the **New York Times** ([9/12/18](https://nyti.ms/2MqieXJ)) describe as “malign behavior,” is a principal justification for US support of Saudi Arabia, including the[ US-supplied bombs](https://www.cnn.com/2018/08/17/middleeast/us-saudi-yemen-bus-strike-intl/index.html) that recently ended the brief lives of over 40 Yemeni schoolchildren. Lockheed Martin’s stock is [up 34 percent](https://www.marketwatch.com/investing/stock/LMT/historical?siteid=mktw&date=01%2F20%2F2017)from Trump’s inauguration day.
|
||||||
|
|
||||||
|
Corporate media go beyond a simple coverup of Saudi crimes to evangelize their leadership as the liberal antidote to Iran’s “theocracy.” Who can forget Thomas Friedman’s revolting puff piece for the Saudi crown prince Mohammad bin Salman? Extensively quoting Salman (**New York Times**, [11/23/17](https://nyti.ms/2i0mwfg)), who refers to Iranian Ayatollah Ali Khamenei as “the new Hitler of the Middle East,” Friedman nevertheless remains pessimistic about whether “MBS and his team” can see their stand against Iran through, as “dysfunction and rivalries within the Sunni Arab world generally have prevented forming a unified front.” Oh well, every team needs cheerleaders, and Friedman isn’t just a fair-weather fan.
|
||||||
|
|
||||||
|
While Friedman (**New York Times**, [5/15/18](https://nyti.ms/2GmBgLo)) believes that Trump has drawn “some needed attention to Iran’s bad behavior,” for him pivotal questions remain unanswered, such as “who is going to take over in Tehran if the current Islamic regime collapses?” One immediate fix he proposed was to censure Iran’s metaphorical “occupation” of Syria, Iraq and Lebanon. Isn’t this ironic coming from an unapologetic propagandist for Washington’s decades-long, non-metaphorical occupation of the two countries to the east and west of Iran (**FAIR.org**, [12/9/15](https://fair.org/home/friedman-goes-after-trump-hey-massive-bombing-was-my-idea/))?
|
||||||
|
|
||||||
|
In a surprising break from corporate media convention, **USA Today** ([9/26/18](https://www.usatoday.com/story/opinion/voices/2018/09/26/iran-united-states-foreign-policy-iraq-war-column/1379872002/)) published a column on US/Iran relations written by an actual Iranian. Reflecting on the [CIA-orchestrated coup](https://en.wikipedia.org/wiki/1953_Iranian_coup_d%27%C3%A9tat) against Iran’s elected government in 1953, Azadeh Shahshahani, who was born four days after the 1979 revolution there, wrote:
|
||||||
|
|
||||||
|
> “I often wonder what would have happened if that coup had not worked, if \[Prime Minister\] Mosaddeq had been allowed to govern, if democracy had been allowed to flourish.”
|
||||||
|
|
||||||
|
“It is time for the US government to stop intervening in Iran and let the Iranian people determine their own destiny,” she beseeched readers.
|
||||||
|
|
||||||
|
![](https://theantimedia.com/wp-content/uploads/2018/10/Real-News-Code-Pink-610x343.png)Code Pink’s Medea Benjamin confronts the head of Trump’s “Iran Action Group” (**Real News**, [9/21/18](https://youtu.be/peJGmeg6ZE8)).Shahshahani’s call is supported by some who have rejected corporate media’s war propaganda and have gone to extreme lengths to have their perspectives heard. Anti-war activist and Code Pink founder Medea Benjamin was recently forcibly removed after she upstaged Brian Hook, leader of Trump’s Iran Action Group, on live TV, calling his press conference “the most ridiculous thing I have ever seen” (**Real News**, [9/21/18](https://youtu.be/peJGmeg6ZE8)). Benjamin implored the audience: “Let’s talk about Saudi Arabia. Is that who our allies are?”
|
||||||
|
|
||||||
|
“How dare you bring up the issue of Yemen,” admonished Benjamin as she was dragged from the room. “It’s the Saudi bombing that is killing most people in Yemen. So let’s get real. No more war! Peace with Iran!” Code Pink is [currently petitioning](https://www.codepink.org/dont_iraq_iran?utm_campaign=iran_national_sept25) the **New York Times** and **Washington Post** to stop propagandizing war.
|
||||||
|
|
||||||
|
Sadly, no matter whom you ask in corporate media, be they spokespeople for “Trump’s America” or “the resistance,” peace remains an elusive choice in the US political imagination. And while the public was focused last week on Supreme Court nominee [Brett Kavanaugh’s ](https://youtu.be/7zVOkb3CdZ0)[perjurious testimony](https://www.currentaffairs.org/2018/09/how-we-know-kavanaugh-is-lying), the Senate finalized a[$674 billion “defense” budget](https://www.democracynow.org/2018/9/20/headlines/senate_passes_674_billion_military_spending_bill). Every single Democrat in the chamber voted in favor of the bill, [explicitly naming Iran](https://www.congress.gov/bill/115th-congress/house-bill/6157/text) as persona non grata in the United States’[world-leading arms supply network](https://www.sipri.org/news/press-release/2018/asia-and-middle-east-lead-rising-trend-arms-imports-us-exports-grow-significantly-says-sipri), which has seen a 25 percent increase in exports since Obama took office in 2009.
|
||||||
|
|
||||||
|
The US government’s imperial ambitions are perhaps its only truly bipartisan project—what the **New York Times** euphemistically refers to as “globalism.” Nowhere was this on fuller display than at the funeral for Republican Sen. John McCain (**FAIR.org**,[ 9/11/18](https://fair.org/home/maverick-media-use-mccain-funeral-to-shore-up-us-imperialism/)), where politicians of all stripes were tripping over themselves to produce the best accolades for a man who [infamously sang](https://youtu.be/o-zoPgv_nYg)“bomb bomb bomb, bomb bomb Iran” to the tune of a Beach Boys song.
|
||||||
|
|
||||||
|
McCain’s bloodlust was nothing new. Nearly a hundred years ago, after the West’s imperial competition culminated in the most destructive war the world had ever seen, the brilliant American sociologist and anti-colonial author WEB Du Bois [wrote](https://www.gutenberg.org/files/15210/15210-h/15210-h.htm), “This is not Europe gone mad; this is not aberration nor insanity; this *is* Europe.”
|
||||||
|
|
||||||
|
Iranian leaders have repeatedly said they do not want war with the US (**AP**, [9/27/18](https://apnews.com/1cb23ee1641041c5910595715f2ea334)), but US corporate media, despite frequently characterizing Trump as a “mad king” (**FAIR.org**, [6/13/18](https://fair.org/home/why-do-us-media-only-worry-about-one-authoritarians-nukes/)), continue to play an instrumental role in rationalizing a future war with Iran. Should such an intentional catastrophe come to pass, we can hardly say that this would be America gone mad; war is not aberration, it is always presented as the next sane choice. This *is* America.
|
||||||
|
|
||||||
|
*By [John C. O’Day](https://fair.org/author/john-c-oday/) / Republished with permission / [FAIR.org](https://fair.org/) / [Report a typo](mailto:edits@theantimedia.org)*
|
||||||
|
|
||||||
|
*This article was chosen for republication based on the interest of our readers. Anti-Media republishes stories from a number of other independent news sources. The views expressed in this article are the author’s own and do not reflect Anti-Media editorial policy.*
|
38
tests/test-lbry_network_parser.php
Normal file
38
tests/test-lbry_network_parser.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class LBRYPressTest
|
||||||
|
*
|
||||||
|
* @package Lbrypress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case for primary plugin class
|
||||||
|
*/
|
||||||
|
class LBRY_Network_Parser_Test extends WP_UnitTestCase
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->class_instance = new LBRY_Network_Parser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_convert_to_markdown()
|
||||||
|
{
|
||||||
|
$content = file_get_contents(LBRY_ABSPATH . 'tests/convert_content.txt');
|
||||||
|
$post = self::factory()->post->create_and_get(array(
|
||||||
|
'post_title' => 'Markdown Test!',
|
||||||
|
'post_content' => $content
|
||||||
|
));
|
||||||
|
$attachment = $this->factory->attachment->create_and_get(array(
|
||||||
|
'post_parent' => $post->ID,
|
||||||
|
'file' => '/wp-content/uploads/2018/08/BBC-John-Bolton-610x343.jpg'
|
||||||
|
));
|
||||||
|
add_post_meta($post->ID, '_thumbnail_id', $attachment->ID, true);
|
||||||
|
|
||||||
|
$actual = fopen(LBRY_ABSPATH . 'tests/convert_actual.md', 'w');
|
||||||
|
$converted = $this->class_instance->convert_to_markdown($post->ID);
|
||||||
|
fwrite($actual, $converted);
|
||||||
|
$this->assertFileEquals(LBRY_ABSPATH . 'tests/convert_expected.md', LBRY_ABSPATH . 'tests/convert_actual.md');
|
||||||
|
}
|
||||||
|
}
|
38
tests/test-lbrypress.php
Normal file
38
tests/test-lbrypress.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class LBRYPressTest
|
||||||
|
*
|
||||||
|
* @package Lbrypress
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test case for primary plugin class
|
||||||
|
*/
|
||||||
|
class LBRYPressTest extends WP_UnitTestCase
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->class_instance = LBRYPress::instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_init()
|
||||||
|
{
|
||||||
|
// Init is called during constructor
|
||||||
|
$this->assertInstanceOf(LBRY_Daemon::class, $this->class_instance->daemon);
|
||||||
|
$this->assertInstanceOf(LBRY_Speech::class, $this->class_instance->speech);
|
||||||
|
$this->assertInstanceOf(LBRY_Admin_Notice::class, $this->class_instance->notice);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends test_init
|
||||||
|
* Test activation hook
|
||||||
|
*/
|
||||||
|
public function test_activate()
|
||||||
|
{
|
||||||
|
// Make sure we have options when activated
|
||||||
|
$this->class_instance->activate();
|
||||||
|
$this->assertTrue(!empty(get_option(LBRY_SETTINGS)));
|
||||||
|
}
|
||||||
|
}
|
0
tmp/.gitkeep
Normal file
0
tmp/.gitkeep
Normal file
7
vendor/autoload.php
vendored
Normal file
7
vendor/autoload.php
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit657fe71ab231d7a3522553857156496d::getLoader();
|
445
vendor/composer/ClassLoader.php
vendored
Normal file
445
vendor/composer/ClassLoader.php
vendored
Normal file
|
@ -0,0 +1,445 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see http://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see http://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
// PSR-4
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
private $useIncludePath = false;
|
||||||
|
private $classMap = array();
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
private $missingClasses = array();
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $classMap Class to filename map
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
(array) $paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
(array) $paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param array|string $paths The PSR-0 base directories
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return bool|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath.'\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*/
|
||||||
|
function includeFile($file)
|
||||||
|
{
|
||||||
|
include $file;
|
||||||
|
}
|
9
vendor/composer/autoload_classmap.php
vendored
Normal file
9
vendor/composer/autoload_classmap.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
10
vendor/composer/autoload_psr4.php
vendored
Normal file
10
vendor/composer/autoload_psr4.php
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'League\\HTMLToMarkdown\\' => array($vendorDir . '/league/html-to-markdown/src'),
|
||||||
|
);
|
52
vendor/composer/autoload_real.php
vendored
Normal file
52
vendor/composer/autoload_real.php
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInit657fe71ab231d7a3522553857156496d
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInit657fe71ab231d7a3522553857156496d', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInit657fe71ab231d7a3522553857156496d', 'loadClassLoader'));
|
||||||
|
|
||||||
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
||||||
|
if ($useStaticLoader) {
|
||||||
|
require_once __DIR__ . '/autoload_static.php';
|
||||||
|
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInit657fe71ab231d7a3522553857156496d::getInitializer($loader));
|
||||||
|
} else {
|
||||||
|
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||||
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->set($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$map = require __DIR__ . '/autoload_psr4.php';
|
||||||
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->setPsr4($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||||
|
if ($classMap) {
|
||||||
|
$loader->addClassMap($classMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
31
vendor/composer/autoload_static.php
vendored
Normal file
31
vendor/composer/autoload_static.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInit657fe71ab231d7a3522553857156496d
|
||||||
|
{
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'L' =>
|
||||||
|
array (
|
||||||
|
'League\\HTMLToMarkdown\\' => 22,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'League\\HTMLToMarkdown\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/league/html-to-markdown/src',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInit657fe71ab231d7a3522553857156496d::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInit657fe71ab231d7a3522553857156496d::$prefixDirsPsr4;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
68
vendor/composer/installed.json
vendored
Normal file
68
vendor/composer/installed.json
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "league/html-to-markdown",
|
||||||
|
"version": "4.8.0",
|
||||||
|
"version_normalized": "4.8.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/html-to-markdown.git",
|
||||||
|
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/f9a879a068c68ff47b722de63f58bec79e448f9d",
|
||||||
|
"reference": "f9a879a068c68ff47b722de63f58bec79e448f9d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||||
|
"phpunit/phpunit": "4.*",
|
||||||
|
"scrutinizer/ocular": "~1.1"
|
||||||
|
},
|
||||||
|
"time": "2018-09-18T12:18:08+00:00",
|
||||||
|
"bin": [
|
||||||
|
"bin/html-to-markdown"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.9-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\HTMLToMarkdown\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nick Cernis",
|
||||||
|
"email": "nick@cern.is",
|
||||||
|
"homepage": "http://modernnerd.net",
|
||||||
|
"role": "Original Author"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Colin O'Dell",
|
||||||
|
"email": "colinodell@gmail.com",
|
||||||
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||||
|
"homepage": "https://github.com/thephpleague/html-to-markdown",
|
||||||
|
"keywords": [
|
||||||
|
"html",
|
||||||
|
"markdown"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
267
vendor/league/html-to-markdown/CHANGELOG.md
vendored
Normal file
267
vendor/league/html-to-markdown/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
# Change Log
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
|
||||||
|
|
||||||
|
## [Unreleased][unreleased]
|
||||||
|
|
||||||
|
## [4.8.0] - 2018-09-18
|
||||||
|
### Added
|
||||||
|
- Added support for email auto-linking
|
||||||
|
- Added a new interface (`HtmlConverterInterface`) for the main `HtmlConverter` class
|
||||||
|
- Added additional test cases (#14)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- The `italic_style` option now defaults to `'*'` so that in-word emphasis is handled properly (#75)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed several issues of `<code>` and `<pre>` tags not converting to blocks or inlines properly (#26, #70, #102, #140, #161, #162)
|
||||||
|
- Fixed in-word emphasis using underscores as delimiter (#75)
|
||||||
|
- Fixed character escaping inside of `<div>` elements
|
||||||
|
- Fixed header edge cases
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
- The `bold_style` and `italic_style` options have been deprecated (#75)
|
||||||
|
|
||||||
|
## [4.7.0] - 2018-05-19
|
||||||
|
### Added
|
||||||
|
- Added `setOptions()` function for chainable calling (#149)
|
||||||
|
- Added new `list_item_style_alternate` option for converting every-other list with a different character (#155)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed insufficient newlines after code blocks (#144, #148)
|
||||||
|
- Fixed trailing spaces not being preserved in link anchors (#157)
|
||||||
|
- Fixed list-like lines not being escaped inside of lists items (#159)
|
||||||
|
|
||||||
|
## [4.6.2]
|
||||||
|
### Fixed
|
||||||
|
- Fixed issue with emphasized spaces (#146)
|
||||||
|
|
||||||
|
## [4.6.1]
|
||||||
|
### Fixed
|
||||||
|
- Fixed conversion of `<pre>` tags (#145)
|
||||||
|
|
||||||
|
## [4.6.0]
|
||||||
|
### Added
|
||||||
|
- Added support for ordered lists starting at numbers other than 1
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed overly-eager escaping of list-like text (#141)
|
||||||
|
|
||||||
|
## [4.5.0]
|
||||||
|
### Added
|
||||||
|
- Added configuration option for list item style (#135, #136)
|
||||||
|
|
||||||
|
## [4.4.1]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed autolinking of invalid URLs (#129)
|
||||||
|
|
||||||
|
## [4.4.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added `hard_break` configuration option (#112, #115)
|
||||||
|
- The `HtmlConverter` can now be instantiated with an `Environment` (#118)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed handling of paragraphs in list item elements (#47, #110)
|
||||||
|
- Fixed phantom spaces when newlines follow `br` elements (#116, #117)
|
||||||
|
- Fixed link converter not sanitizing inner spaces properly (#119, #120)
|
||||||
|
|
||||||
|
## [4.3.1]
|
||||||
|
### Changed
|
||||||
|
- Revised the sanitization implementation (#109)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed tag-like content not being escaped (#67, #109)
|
||||||
|
- Fixed thematic break-like content not being escaped (#65, #109)
|
||||||
|
- Fixed codefence-like content not being escaped (#64, #109)
|
||||||
|
|
||||||
|
## [4.3.0]
|
||||||
|
### Added
|
||||||
|
- Added full support for PHP 7.0 and 7.1
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Changed `<pre>` and `<pre><code>` conversions to use backticks instead of indendation (#102)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed issue where specified code language was not preserved (#70, #102)
|
||||||
|
- Fixed issue where `<code>` tags nested in `<pre>` was not converted properly (#70, #102)
|
||||||
|
- Fixed header-like content not being escaped (#76, #105)
|
||||||
|
- Fixed blockquote-like content not being escaped (#77, #103)
|
||||||
|
- Fixed ordered list-like content not being escaped (#73, #106)
|
||||||
|
- Fixed unordered list-like content not being escaped (#71, #107)
|
||||||
|
|
||||||
|
## [4.2.2]
|
||||||
|
### Fixed
|
||||||
|
- Fixed sanitization bug which sometimes removes desired content (#63, #101)
|
||||||
|
|
||||||
|
## [4.2.1]
|
||||||
|
### Fixed
|
||||||
|
- Fixed path to autoload.php when used as a library (#98)
|
||||||
|
- Fixed edge case for tags containing only whitespace (#99)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Removed double HTML entity decoding, as this is not desireable (#60)
|
||||||
|
|
||||||
|
## [4.2.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added the ability to invoke HtmlConverter objects as functions (#85)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed improper handling of nested list items (#19 and #84)
|
||||||
|
- Fixed preceeding or trailing spaces within emphasis tags (#83)
|
||||||
|
|
||||||
|
## [4.1.1]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed conversion of empty paragraphs (#78)
|
||||||
|
- Fixed `preg_replace` so it wouldn't break UTF-8 characters (#79)
|
||||||
|
|
||||||
|
## [4.1.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added `bin/html-to-markdown` script
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Changed default italic character to `_` (#58)
|
||||||
|
|
||||||
|
## [4.0.1]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Added escaping to avoid * and _ in a text being rendered as emphasis (#48)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Removed the demo (#51)
|
||||||
|
- `.styleci.yml` and `CONTRIBUTING.md` are no longer included in distributions (#50)
|
||||||
|
|
||||||
|
## [4.0.0]
|
||||||
|
|
||||||
|
This release changes the visibility of several methods/properties. #42 and #43 brought to light that some visiblities were
|
||||||
|
not ideally set, so this releases fixes that. Moving forwards this should reduce the chance of introducing BC-breaking changes.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added new `HtmlConverter::getEnvironment()` method to expose the `Environment` (#42, #43)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Changed `Environment::addConverter()` from `protected` to `public`, enabling custom converters to be added (#42, #43)
|
||||||
|
- Changed `HtmlConverter::createDOMDocument()` from `protected` to `private`
|
||||||
|
- Changed `Element::nextCached` from `protected` to `private`
|
||||||
|
- Made the `Environment` class `final`
|
||||||
|
|
||||||
|
## [3.1.1]
|
||||||
|
### Fixed
|
||||||
|
- Empty HTML strings now result in empty Markdown documents (#40, #41)
|
||||||
|
|
||||||
|
## [3.1.0]
|
||||||
|
### Added
|
||||||
|
- Added new `equals` method to `Element` to check for equality
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Use Linux line endings consistently instead of plaform-specific line endings (#36)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Cleaned up code style
|
||||||
|
|
||||||
|
## [3.0.0]
|
||||||
|
### Changed
|
||||||
|
- Changed namespace to `League\HTMLToMarkdown`
|
||||||
|
- Changed packagist name to `league/html-to-markdown`
|
||||||
|
- Re-organized code into several separate classes
|
||||||
|
- `<a>` tags with identical href and inner text are now rendered using angular bracket syntax (#31)
|
||||||
|
- `<div>` elements are now treated as block-level elements (#33)
|
||||||
|
|
||||||
|
## [2.2.2]
|
||||||
|
### Added
|
||||||
|
- Added support for PHP 5.6 and HHVM
|
||||||
|
- Enabled testing against PHP 7 nightlies
|
||||||
|
- Added this CHANGELOG.md
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed whitespace preservation between inline elements (#9 and #10)
|
||||||
|
|
||||||
|
## [2.2.1]
|
||||||
|
### Fixed
|
||||||
|
- Preserve placeholder links (#22)
|
||||||
|
|
||||||
|
## [2.2.0]
|
||||||
|
### Added
|
||||||
|
- Added CircleCI config
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `<pre>` blocks are now treated as code elements
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Dropped support for PHP 5.2
|
||||||
|
- Removed incorrect README comment regarding `#text` nodes (#17)
|
||||||
|
|
||||||
|
## [2.1.2]
|
||||||
|
### Added
|
||||||
|
- Added the ability to blacklist/remove specific node types (#11)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Line breaks are now placed after divs instead of before them
|
||||||
|
- Newlines inside of link texts are now removed
|
||||||
|
- Updated the minimum PHPUnit version to 4.*
|
||||||
|
|
||||||
|
## [2.1.1]
|
||||||
|
### Added
|
||||||
|
- Added options to customize emphasis characters
|
||||||
|
|
||||||
|
## [2.1.0]
|
||||||
|
### Added
|
||||||
|
- Added option to strip HTML tags without Markdown equivalents
|
||||||
|
- Added `convert()` method for converter reuse
|
||||||
|
- Added ability to set options after instance construction
|
||||||
|
- Documented the required PHP extensions (#4)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- ATX style now used for h1 and h2 tags inside blockquotes
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Newlines inside blockquotes are now started with a bracket
|
||||||
|
- Fixed some incorrect docblocks
|
||||||
|
- `__toString()` now returns an empty string if input is empty
|
||||||
|
- Convert head tag if body tag is empty (#7)
|
||||||
|
- Preserve special characters inside tags without md equivalents (#6)
|
||||||
|
|
||||||
|
|
||||||
|
## [2.0.1]
|
||||||
|
### Fixed
|
||||||
|
- Fixed first line indentation for multi-line code blocks
|
||||||
|
- Fixed consecutive anchors get separating spaces stripped (#3)
|
||||||
|
|
||||||
|
## [2.0.0]
|
||||||
|
### Added
|
||||||
|
- Initial release
|
||||||
|
|
||||||
|
[unreleased]: https://github.com/thephpleague/html-to-markdown/compare/4.8.0...master
|
||||||
|
[4.8.0]: https://github.com/thephpleague/html-to-markdown/compare/4.7.0...4.8.0
|
||||||
|
[4.7.0]: https://github.com/thephpleague/html-to-markdown/compare/4.6.2...4.7.0
|
||||||
|
[4.6.2]: https://github.com/thephpleague/html-to-markdown/compare/4.6.1...4.6.2
|
||||||
|
[4.6.1]: https://github.com/thephpleague/html-to-markdown/compare/4.6.0...4.6.1
|
||||||
|
[4.6.0]: https://github.com/thephpleague/html-to-markdown/compare/4.5.0...4.6.0
|
||||||
|
[4.5.0]: https://github.com/thephpleague/html-to-markdown/compare/4.4.1...4.5.0
|
||||||
|
[4.4.1]: https://github.com/thephpleague/html-to-markdown/compare/4.4.0...4.4.1
|
||||||
|
[4.4.0]: https://github.com/thephpleague/html-to-markdown/compare/4.3.1...4.4.0
|
||||||
|
[4.3.1]: https://github.com/thephpleague/html-to-markdown/compare/4.3.0...4.3.1
|
||||||
|
[4.3.0]: https://github.com/thephpleague/html-to-markdown/compare/4.2.2...4.3.0
|
||||||
|
[4.2.2]: https://github.com/thephpleague/html-to-markdown/compare/4.2.1...4.2.2
|
||||||
|
[4.2.1]: https://github.com/thephpleague/html-to-markdown/compare/4.2.0...4.2.1
|
||||||
|
[4.2.0]: https://github.com/thephpleague/html-to-markdown/compare/4.1.1...4.2.0
|
||||||
|
[4.1.1]: https://github.com/thephpleague/html-to-markdown/compare/4.1.0...4.1.1
|
||||||
|
[4.1.0]: https://github.com/thephpleague/html-to-markdown/compare/4.0.1...4.1.0
|
||||||
|
[4.0.1]: https://github.com/thephpleague/html-to-markdown/compare/4.0.0...4.0.1
|
||||||
|
[4.0.0]: https://github.com/thephpleague/html-to-markdown/compare/3.1.1...4.0.0
|
||||||
|
[3.1.1]: https://github.com/thephpleague/html-to-markdown/compare/3.1.0...3.1.1
|
||||||
|
[3.1.0]: https://github.com/thephpleague/html-to-markdown/compare/3.0.0...3.1.0
|
||||||
|
[3.0.0]: https://github.com/thephpleague/html-to-markdown/compare/2.2.2...3.0.0
|
||||||
|
[2.2.2]: https://github.com/thephpleague/html-to-markdown/compare/2.2.1...2.2.2
|
||||||
|
[2.2.1]: https://github.com/thephpleague/html-to-markdown/compare/2.2.0...2.2.1
|
||||||
|
[2.2.0]: https://github.com/thephpleague/html-to-markdown/compare/2.1.2...2.2.0
|
||||||
|
[2.1.2]: https://github.com/thephpleague/html-to-markdown/compare/2.1.1...2.1.2
|
||||||
|
[2.1.1]: https://github.com/thephpleague/html-to-markdown/compare/2.1.0...2.1.1
|
||||||
|
[2.1.0]: https://github.com/thephpleague/html-to-markdown/compare/2.0.1...2.1.0
|
||||||
|
[2.0.1]: https://github.com/thephpleague/html-to-markdown/compare/2.0.0...2.0.1
|
||||||
|
[2.0.0]: https://github.com/thephpleague/html-to-markdown/compare/775f91e...2.0.0
|
||||||
|
|
22
vendor/league/html-to-markdown/CONDUCT.md
vendored
Normal file
22
vendor/league/html-to-markdown/CONDUCT.md
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Contributor Code of Conduct
|
||||||
|
|
||||||
|
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||||
|
|
||||||
|
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery
|
||||||
|
* Personal attacks
|
||||||
|
* Trolling or insulting/derogatory comments
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
||||||
|
* Other unethical or unprofessional conduct.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||||
|
|
||||||
|
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
196
vendor/league/html-to-markdown/README.md
vendored
Normal file
196
vendor/league/html-to-markdown/README.md
vendored
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
HTML To Markdown for PHP
|
||||||
|
========================
|
||||||
|
|
||||||
|
[![Join the chat at https://gitter.im/thephpleague/html-to-markdown](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/thephpleague/html-to-markdown?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
[![Latest Version](https://img.shields.io/packagist/v/league/html-to-markdown.svg?style=flat-square)](https://packagist.org/packages/league/html-to-markdown)
|
||||||
|
[![Software License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
|
||||||
|
[![Build Status](https://img.shields.io/travis/thephpleague/html-to-markdown/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/html-to-markdown)
|
||||||
|
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/html-to-markdown.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/html-to-markdown/code-structure)
|
||||||
|
[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/html-to-markdown.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/html-to-markdown)
|
||||||
|
[![Total Downloads](https://img.shields.io/packagist/dt/league/html-to-markdown.svg?style=flat-square)](https://packagist.org/packages/league/html-to-markdown)
|
||||||
|
|
||||||
|
Library which converts HTML to [Markdown](http://daringfireball.net/projects/markdown/) for your sanity and convenience.
|
||||||
|
|
||||||
|
|
||||||
|
**Requires**: PHP 5.3+ or PHP 7.0+
|
||||||
|
|
||||||
|
**Lead Developer**: [@colinodell](http://twitter.com/colinodell)
|
||||||
|
|
||||||
|
**Original Author**: [@nickcernis](http://twitter.com/nickcernis)
|
||||||
|
|
||||||
|
|
||||||
|
### Why convert HTML to Markdown?
|
||||||
|
|
||||||
|
*"What alchemy is this?"* you mutter. *"I can see why you'd convert [Markdown to HTML](https://github.com/thephpleague/commonmark),"* you continue, already labouring the question somewhat, *"but why go the other way?"*
|
||||||
|
|
||||||
|
Typically you would convert HTML to Markdown if:
|
||||||
|
|
||||||
|
1. You have an existing HTML document that needs to be edited by people with good taste.
|
||||||
|
2. You want to store new content in HTML format but edit it as Markdown.
|
||||||
|
3. You want to convert HTML email to plain text email.
|
||||||
|
4. You know a guy who's been converting HTML to Markdown for years, and now he can speak Elvish. You'd quite like to be able to speak Elvish.
|
||||||
|
5. You just really like Markdown.
|
||||||
|
|
||||||
|
### How to use it
|
||||||
|
|
||||||
|
Require the library by issuing this command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require league/html-to-markdown
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `require 'vendor/autoload.php';` to the top of your script.
|
||||||
|
|
||||||
|
Next, create a new HtmlConverter instance, passing in your valid HTML code to its `convert()` function:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use League\HTMLToMarkdown\HtmlConverter;
|
||||||
|
|
||||||
|
$converter = new HtmlConverter();
|
||||||
|
|
||||||
|
$html = "<h3>Quick, to the Batpoles!</h3>";
|
||||||
|
$markdown = $converter->convert($html);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `$markdown` variable now contains the Markdown version of your HTML as a string:
|
||||||
|
|
||||||
|
```php
|
||||||
|
echo $markdown; // ==> ### Quick, to the Batpoles!
|
||||||
|
```
|
||||||
|
|
||||||
|
The included `demo` directory contains an HTML->Markdown conversion form to try out.
|
||||||
|
|
||||||
|
### Conversion options
|
||||||
|
|
||||||
|
By default, HTML To Markdown preserves HTML tags without Markdown equivalents, like `<span>` and `<div>`.
|
||||||
|
|
||||||
|
To strip HTML tags that don't have a Markdown equivalent while preserving the content inside them, set `strip_tags` to true, like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$converter = new HtmlConverter(array('strip_tags' => true));
|
||||||
|
|
||||||
|
$html = '<span>Turnips!</span>';
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains "Turnips!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or more explicitly, like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$converter = new HtmlConverter();
|
||||||
|
$converter->getConfig()->setOption('strip_tags', true);
|
||||||
|
|
||||||
|
$html = '<span>Turnips!</span>';
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains "Turnips!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that only the tags themselves are stripped, not the content they hold.
|
||||||
|
|
||||||
|
To strip tags and their content, pass a space-separated list of tags in `remove_nodes`, like this:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$converter = new HtmlConverter(array('remove_nodes' => 'span div'));
|
||||||
|
|
||||||
|
$html = '<span>Turnips!</span><div>Monkeys!</div>';
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains ""
|
||||||
|
```
|
||||||
|
|
||||||
|
### Style options
|
||||||
|
|
||||||
|
By default bold tags are converted using the asterisk syntax, and italic tags are converted using the underlined syntax. Change these by using the `bold_style` and `italic_style` options.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$converter = new HtmlConverter();
|
||||||
|
$converter->getConfig()->setOption('italic_style', '*');
|
||||||
|
$converter->getConfig()->setOption('bold_style', '__');
|
||||||
|
|
||||||
|
$html = '<em>Italic</em> and a <strong>bold</strong>';
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains "*Italic* and a __bold__"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Line break options
|
||||||
|
|
||||||
|
By default, `br` tags are converted to two spaces followed by a newline character as per [traditional Markdown](https://daringfireball.net/projects/markdown/syntax#p). Set `hard_break` to `true` to omit the two spaces, as per GitHub Flavored Markdown (GFM).
|
||||||
|
|
||||||
|
```php
|
||||||
|
$converter = new HtmlConverter();
|
||||||
|
$html = '<p>test<br>line break</p>';
|
||||||
|
|
||||||
|
$converter->getConfig()->setOption('hard_break', true);
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains "test\nline break"
|
||||||
|
|
||||||
|
$converter->getConfig()->setOption('hard_break', false); // default
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains "test \nline break"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Passing custom Environment object
|
||||||
|
|
||||||
|
You can pass current `Environment` object to customize i.e. which converters should be used.
|
||||||
|
|
||||||
|
```php
|
||||||
|
$environment = new Environment(array(
|
||||||
|
// your configuration here
|
||||||
|
));
|
||||||
|
$environment->addConverter(new HeaderConverter()); // optionally - add converter manually
|
||||||
|
|
||||||
|
$converter = new HtmlConverter($environment);
|
||||||
|
|
||||||
|
$html = '<h3>Header</h3>
|
||||||
|
<img src="" />
|
||||||
|
';
|
||||||
|
$markdown = $converter->convert($html); // $markdown now contains "### Header" and "<img src="" />"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Limitations
|
||||||
|
|
||||||
|
- Markdown Extra, MultiMarkdown and other variants aren't supported – just Markdown.
|
||||||
|
|
||||||
|
### Known issues
|
||||||
|
|
||||||
|
- Nested lists and lists containing multiple paragraphs aren't converted correctly.
|
||||||
|
- Lists inside blockquotes aren't converted correctly.
|
||||||
|
- Any reported [open issues here](https://github.com/thephpleague/html-to-markdown/issues?state=open).
|
||||||
|
|
||||||
|
[Report your issue or request a feature here.](https://github.com/thephpleague/html-to-markdown/issues/new) Issues with patches or failing tests are especially welcome.
|
||||||
|
|
||||||
|
### Style notes
|
||||||
|
|
||||||
|
- Setext (underlined) headers are the default for H1 and H2. If you prefer the ATX style for H1 and H2 (# Header 1 and ## Header 2), set `header_style` to 'atx' in the options array when you instantiate the object:
|
||||||
|
|
||||||
|
`$converter = new HtmlConverter(array('header_style'=>'atx'));`
|
||||||
|
|
||||||
|
Headers of H3 priority and lower always use atx style.
|
||||||
|
|
||||||
|
- Links and images are referenced inline. Footnote references (where image src and anchor href attributes are listed in the footnotes) are not used.
|
||||||
|
- Blockquotes aren't line wrapped – it makes the converted Markdown easier to edit.
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
HTML To Markdown requires PHP's [xml](http://www.php.net/manual/en/xml.installation.php), [lib-xml](http://www.php.net/manual/en/libxml.installation.php), and [dom](http://www.php.net/manual/en/dom.installation.php) extensions, all of which are enabled by default on most distributions.
|
||||||
|
|
||||||
|
Errors such as "Fatal error: Class 'DOMDocument' not found" on distributions such as CentOS that disable PHP's xml extension can be resolved by installing php-xml.
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Many thanks to all [contributors](https://github.com/thephpleague/html-to-markdown/graphs/contributors) so far. Further improvements and feature suggestions are very welcome.
|
||||||
|
|
||||||
|
### How it works
|
||||||
|
|
||||||
|
HTML To Markdown creates a DOMDocument from the supplied HTML, walks through the tree, and converts each node to a text node containing the equivalent markdown, starting from the most deeply nested node and working inwards towards the root node.
|
||||||
|
|
||||||
|
### To-do
|
||||||
|
|
||||||
|
- Support for nested lists and lists inside blockquotes.
|
||||||
|
- Offer an option to preserve tags as HTML if they contain attributes that can't be represented with Markdown (e.g. `style`).
|
||||||
|
|
||||||
|
### Trying to convert Markdown to HTML?
|
||||||
|
|
||||||
|
Use one of these great libraries:
|
||||||
|
|
||||||
|
- [league/commonmark](https://github.com/thephpleague/commonmark) (recommended)
|
||||||
|
- [cebe/markdown](https://github.com/cebe/markdown)
|
||||||
|
- [PHP Markdown](https://michelf.ca/projects/php-markdown/)
|
||||||
|
- [Parsedown](https://github.com/erusev/parsedown)
|
||||||
|
|
||||||
|
No guarantees about the Elvish, though.
|
||||||
|
|
48
vendor/league/html-to-markdown/composer.json
vendored
Normal file
48
vendor/league/html-to-markdown/composer.json
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "league/html-to-markdown",
|
||||||
|
"type": "library",
|
||||||
|
"description": "An HTML-to-markdown conversion helper for PHP",
|
||||||
|
"keywords": ["markdown", "html"],
|
||||||
|
"homepage": "https://github.com/thephpleague/html-to-markdown",
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Colin O'Dell",
|
||||||
|
"email": "colinodell@gmail.com",
|
||||||
|
"homepage": "https://www.colinodell.com",
|
||||||
|
"role": "Lead Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nick Cernis",
|
||||||
|
"email": "nick@cern.is",
|
||||||
|
"homepage": "http://modernnerd.net",
|
||||||
|
"role": "Original Author"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\HTMLToMarkdown\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\HTMLToMarkdown\\Test\\": "tests"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-xml": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mikehaertl/php-shellcommand": "~1.1.0",
|
||||||
|
"phpunit/phpunit": "4.*",
|
||||||
|
"scrutinizer/ocular": "~1.1"
|
||||||
|
},
|
||||||
|
"bin": ["bin/html-to-markdown"],
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.9-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
vendor/league/html-to-markdown/src/Configuration.php
vendored
Normal file
76
vendor/league/html-to-markdown/src/Configuration.php
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
class Configuration
|
||||||
|
{
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $config
|
||||||
|
*/
|
||||||
|
public function __construct(array $config = array())
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
|
||||||
|
$this->checkForDeprecatedOptions($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $config
|
||||||
|
*/
|
||||||
|
public function merge(array $config = array())
|
||||||
|
{
|
||||||
|
$this->checkForDeprecatedOptions($config);
|
||||||
|
$this->config = array_replace_recursive($this->config, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $config
|
||||||
|
*/
|
||||||
|
public function replace(array $config = array())
|
||||||
|
{
|
||||||
|
$this->checkForDeprecatedOptions($config);
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $key
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public function setOption($key, $value)
|
||||||
|
{
|
||||||
|
$this->checkForDeprecatedOptions(array($key => $value));
|
||||||
|
$this->config[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $key
|
||||||
|
* @param mixed|null $default
|
||||||
|
*
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
public function getOption($key = null, $default = null)
|
||||||
|
{
|
||||||
|
if ($key === null) {
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->config[$key])) {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->config[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkForDeprecatedOptions(array $config)
|
||||||
|
{
|
||||||
|
foreach ($config as $key => $value) {
|
||||||
|
if ($key === 'bold_style' && $value !== '**') {
|
||||||
|
@trigger_error('Customizing the bold_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED);
|
||||||
|
} elseif ($key === 'italic_style' && $value !== '*') {
|
||||||
|
@trigger_error('Customizing the italic_style option is deprecated and may be removed in the next major version', E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php
vendored
Normal file
11
vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
interface ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config);
|
||||||
|
}
|
44
vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php
vendored
Normal file
44
vendor/league/html-to-markdown/src/Converter/BlockquoteConverter.php
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class BlockquoteConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
// Contents should have already been converted to Markdown by this point,
|
||||||
|
// so we just need to add '>' symbols to each line.
|
||||||
|
|
||||||
|
$markdown = '';
|
||||||
|
|
||||||
|
$quote_content = trim($element->getValue());
|
||||||
|
|
||||||
|
$lines = preg_split('/\r\n|\r|\n/', $quote_content);
|
||||||
|
|
||||||
|
$total_lines = count($lines);
|
||||||
|
|
||||||
|
foreach ($lines as $i => $line) {
|
||||||
|
$markdown .= '> ' . $line . "\n";
|
||||||
|
if ($i + 1 === $total_lines) {
|
||||||
|
$markdown .= "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $markdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('blockquote');
|
||||||
|
}
|
||||||
|
}
|
79
vendor/league/html-to-markdown/src/Converter/CodeConverter.php
vendored
Normal file
79
vendor/league/html-to-markdown/src/Converter/CodeConverter.php
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class CodeConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$language = '';
|
||||||
|
|
||||||
|
// Checking for language class on the code block
|
||||||
|
$classes = $element->getAttribute('class');
|
||||||
|
|
||||||
|
if ($classes) {
|
||||||
|
// Since tags can have more than one class, we need to find the one that starts with 'language-'
|
||||||
|
$classes = explode(' ', $classes);
|
||||||
|
foreach ($classes as $class) {
|
||||||
|
if (strpos($class, 'language-') !== false) {
|
||||||
|
// Found one, save it as the selected language and stop looping over the classes.
|
||||||
|
$language = str_replace('language-', '', $class);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$markdown = '';
|
||||||
|
$code = html_entity_decode($element->getChildrenAsString());
|
||||||
|
|
||||||
|
// In order to remove the code tags we need to search for them and, in the case of the opening tag
|
||||||
|
// use a regular expression to find the tag and the other attributes it might have
|
||||||
|
$code = preg_replace('/<code\b[^>]*>/', '', $code);
|
||||||
|
$code = str_replace('</code>', '', $code);
|
||||||
|
|
||||||
|
// Checking if it's a code block or span
|
||||||
|
if ($this->shouldBeBlock($element, $code)) {
|
||||||
|
// Code block detected, newlines will be added in parent
|
||||||
|
$markdown .= '```' . $language . "\n" . $code . "\n" . '```';
|
||||||
|
} else {
|
||||||
|
// One line of code, wrapping it on one backtick, removing new lines
|
||||||
|
$markdown .= '`' . preg_replace('/\r\n|\r|\n/', '', $code) . '`';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $markdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('code');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
* @param string $code
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function shouldBeBlock(ElementInterface $element, $code)
|
||||||
|
{
|
||||||
|
if ($element->getParent()->getTagName() == 'pre') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/[^\s]` `/', $code)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
26
vendor/league/html-to-markdown/src/Converter/CommentConverter.php
vendored
Normal file
26
vendor/league/html-to-markdown/src/Converter/CommentConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class CommentConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('#comment');
|
||||||
|
}
|
||||||
|
}
|
20
vendor/league/html-to-markdown/src/Converter/ConverterInterface.php
vendored
Normal file
20
vendor/league/html-to-markdown/src/Converter/ConverterInterface.php
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
interface ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags();
|
||||||
|
}
|
50
vendor/league/html-to-markdown/src/Converter/DefaultConverter.php
vendored
Normal file
50
vendor/league/html-to-markdown/src/Converter/DefaultConverter.php
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Configuration;
|
||||||
|
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class DefaultConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
const DEFAULT_CONVERTER = '_default';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
// If strip_tags is false (the default), preserve tags that don't have Markdown equivalents,
|
||||||
|
// such as <span> nodes on their own. C14N() canonicalizes the node to a string.
|
||||||
|
// See: http://www.php.net/manual/en/domnode.c14n.php
|
||||||
|
if ($this->config->getOption('strip_tags', false)) {
|
||||||
|
return $element->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return html_entity_decode($element->getChildrenAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array(self::DEFAULT_CONVERTER);
|
||||||
|
}
|
||||||
|
}
|
45
vendor/league/html-to-markdown/src/Converter/DivConverter.php
vendored
Normal file
45
vendor/league/html-to-markdown/src/Converter/DivConverter.php
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Configuration;
|
||||||
|
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class DivConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
if ($this->config->getOption('strip_tags', false)) {
|
||||||
|
return $element->getValue() . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return html_entity_decode($element->getChildrenAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('div');
|
||||||
|
}
|
||||||
|
}
|
57
vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php
vendored
Normal file
57
vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Configuration;
|
||||||
|
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class EmphasisConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$tag = $element->getTagName();
|
||||||
|
$value = $element->getValue();
|
||||||
|
|
||||||
|
if (!trim($value)) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tag === 'i' || $tag === 'em') {
|
||||||
|
$style = $this->config->getOption('italic_style');
|
||||||
|
} else {
|
||||||
|
$style = $this->config->getOption('bold_style');
|
||||||
|
}
|
||||||
|
|
||||||
|
$prefix = ltrim($value) !== $value ? ' ' : '';
|
||||||
|
$suffix = rtrim($value) !== $value ? ' ' : '';
|
||||||
|
|
||||||
|
return $prefix . $style . trim($value) . $style . $suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('em', 'i', 'strong', 'b');
|
||||||
|
}
|
||||||
|
}
|
53
vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php
vendored
Normal file
53
vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php
vendored
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Configuration;
|
||||||
|
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class HardBreakConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$return = $this->config->getOption('hard_break') ? "\n" : " \n";
|
||||||
|
|
||||||
|
$next = $element->getNext();
|
||||||
|
if ($next) {
|
||||||
|
$next_value = $next->getValue();
|
||||||
|
if ($next_value) {
|
||||||
|
if (in_array(substr($next_value, 0, 2), array('- ', '* ', '+ '))) {
|
||||||
|
$return .= '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('br');
|
||||||
|
}
|
||||||
|
}
|
82
vendor/league/html-to-markdown/src/Converter/HeaderConverter.php
vendored
Normal file
82
vendor/league/html-to-markdown/src/Converter/HeaderConverter.php
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Configuration;
|
||||||
|
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class HeaderConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
const STYLE_ATX = 'atx';
|
||||||
|
const STYLE_SETEXT = 'setext';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$level = (int) substr($element->getTagName(), 1, 1);
|
||||||
|
$style = $this->config->getOption('header_style', self::STYLE_SETEXT);
|
||||||
|
|
||||||
|
if (strlen($element->getValue()) === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($level === 1 || $level === 2) && !$element->isDescendantOf('blockquote') && $style === self::STYLE_SETEXT) {
|
||||||
|
return $this->createSetextHeader($level, $element->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createAtxHeader($level, $element->getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $level
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function createSetextHeader($level, $content)
|
||||||
|
{
|
||||||
|
$length = function_exists('mb_strlen') ? mb_strlen($content, 'utf-8') : strlen($content);
|
||||||
|
$underline = ($level === 1) ? '=' : '-';
|
||||||
|
|
||||||
|
return $content . "\n" . str_repeat($underline, $length) . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $level
|
||||||
|
* @param string $content
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function createAtxHeader($level, $content)
|
||||||
|
{
|
||||||
|
$prefix = str_repeat('#', $level) . ' ';
|
||||||
|
|
||||||
|
return $prefix . $content . "\n\n";
|
||||||
|
}
|
||||||
|
}
|
26
vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php
vendored
Normal file
26
vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class HorizontalRuleConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
return "- - - - - -\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('hr');
|
||||||
|
}
|
||||||
|
}
|
35
vendor/league/html-to-markdown/src/Converter/ImageConverter.php
vendored
Normal file
35
vendor/league/html-to-markdown/src/Converter/ImageConverter.php
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class ImageConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$src = $element->getAttribute('src');
|
||||||
|
$alt = $element->getAttribute('alt');
|
||||||
|
$title = $element->getAttribute('title');
|
||||||
|
|
||||||
|
if ($title !== '') {
|
||||||
|
// No newlines added. <img> should be in a block-level element.
|
||||||
|
return '![' . $alt . '](' . $src . ' "' . $title . '")';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '![' . $alt . '](' . $src . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('img');
|
||||||
|
}
|
||||||
|
}
|
65
vendor/league/html-to-markdown/src/Converter/LinkConverter.php
vendored
Normal file
65
vendor/league/html-to-markdown/src/Converter/LinkConverter.php
vendored
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class LinkConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$href = $element->getAttribute('href');
|
||||||
|
$title = $element->getAttribute('title');
|
||||||
|
$text = trim($element->getValue(), "\t\n\r\0\x0B");
|
||||||
|
|
||||||
|
if ($title !== '') {
|
||||||
|
$markdown = '[' . $text . '](' . $href . ' "' . $title . '")';
|
||||||
|
} elseif ($href === $text && $this->isValidAutolink($href)) {
|
||||||
|
$markdown = '<' . $href . '>';
|
||||||
|
} elseif ($href === 'mailto:' . $text && $this->isValidEmail($text)) {
|
||||||
|
$markdown = '<' . $text . '>';
|
||||||
|
} else {
|
||||||
|
$markdown = '[' . $text . '](' . $href . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$href) {
|
||||||
|
$markdown = html_entity_decode($element->getChildrenAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $markdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('a');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $href
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isValidAutolink($href)
|
||||||
|
{
|
||||||
|
return preg_match('/^[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*/i', $href) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $email
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isValidEmail($email)
|
||||||
|
{
|
||||||
|
// Email validation is messy business, but this should cover most cases
|
||||||
|
return filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||||
|
}
|
||||||
|
}
|
26
vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php
vendored
Normal file
26
vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class ListBlockConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
return $element->getValue() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('ol', 'ul');
|
||||||
|
}
|
||||||
|
}
|
81
vendor/league/html-to-markdown/src/Converter/ListItemConverter.php
vendored
Normal file
81
vendor/league/html-to-markdown/src/Converter/ListItemConverter.php
vendored
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Configuration;
|
||||||
|
use League\HTMLToMarkdown\ConfigurationAwareInterface;
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class ListItemConverter implements ConverterInterface, ConfigurationAwareInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $listItemStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Configuration $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Configuration $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
// If parent is an ol, use numbers, otherwise, use dashes
|
||||||
|
$list_type = $element->getParent()->getTagName();
|
||||||
|
|
||||||
|
// Add spaces to start for nested list items
|
||||||
|
$level = $element->getListItemLevel($element);
|
||||||
|
|
||||||
|
$prefixForParagraph = str_repeat(' ', $level + 1);
|
||||||
|
$value = trim(implode("\n" . $prefixForParagraph, explode("\n", trim($element->getValue()))));
|
||||||
|
|
||||||
|
// If list item is the first in a nested list, add a newline before it
|
||||||
|
$prefix = '';
|
||||||
|
if ($level > 0 && $element->getSiblingPosition() === 1) {
|
||||||
|
$prefix = "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($list_type === 'ul') {
|
||||||
|
$list_item_style = $this->config->getOption('list_item_style', '-');
|
||||||
|
$list_item_style_alternate = $this->config->getOption('list_item_style_alternate');
|
||||||
|
if (!isset($this->listItemStyle)) {
|
||||||
|
$this->listItemStyle = $list_item_style_alternate ? $list_item_style_alternate : $list_item_style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($list_item_style_alternate && $level == 0 && $element->getSiblingPosition() === 1) {
|
||||||
|
$this->listItemStyle = $this->listItemStyle == $list_item_style ? $list_item_style_alternate : $list_item_style;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prefix . $this->listItemStyle . ' ' . $value . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($list_type === 'ol' && $start = $element->getParent()->getAttribute('start')) {
|
||||||
|
$number = $start + $element->getSiblingPosition() - 1;
|
||||||
|
} else {
|
||||||
|
$number = $element->getSiblingPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prefix . $number . '. ' . $value . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('li');
|
||||||
|
}
|
||||||
|
}
|
125
vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php
vendored
Normal file
125
vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php
vendored
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class ParagraphConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$value = $element->getValue();
|
||||||
|
|
||||||
|
$markdown = '';
|
||||||
|
|
||||||
|
$lines = preg_split('/\r\n|\r|\n/', $value);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
/*
|
||||||
|
* Some special characters need to be escaped based on the position that they appear
|
||||||
|
* The following function will deal with those special cases.
|
||||||
|
*/
|
||||||
|
$markdown .= $this->escapeSpecialCharacters($line);
|
||||||
|
$markdown .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($markdown) !== '' ? rtrim($markdown) . "\n\n" : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('p');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $line
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function escapeSpecialCharacters($line)
|
||||||
|
{
|
||||||
|
$line = $this->escapeFirstCharacters($line);
|
||||||
|
$line = $this->escapeOtherCharacters($line);
|
||||||
|
$line = $this->escapeOtherCharactersRegex($line);
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $line
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function escapeFirstCharacters($line)
|
||||||
|
{
|
||||||
|
$escapable = array(
|
||||||
|
'>',
|
||||||
|
'- ',
|
||||||
|
'+ ',
|
||||||
|
'--',
|
||||||
|
'~~~',
|
||||||
|
'---',
|
||||||
|
'- - -'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($escapable as $i) {
|
||||||
|
if (strpos(ltrim($line), $i) === 0) {
|
||||||
|
// Found a character that must be escaped, adding a backslash before
|
||||||
|
return '\\' . ltrim($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $line
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function escapeOtherCharacters($line)
|
||||||
|
{
|
||||||
|
$escapable = array(
|
||||||
|
'<!--'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($escapable as $i) {
|
||||||
|
if (strpos($line, $i) !== false) {
|
||||||
|
// Found an escapable character, escaping it
|
||||||
|
$line = substr_replace($line, '\\', strpos($line, $i), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $line
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function escapeOtherCharactersRegex($line)
|
||||||
|
{
|
||||||
|
$regExs = array(
|
||||||
|
// Match numbers ending on ')' or '.' that are at the beginning of the line.
|
||||||
|
// They will be escaped if immediately followed by a space or newline.
|
||||||
|
'/^[0-9]+(?=(\)|\.)( |$))/'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($regExs as $i) {
|
||||||
|
if (preg_match($i, $line, $match)) {
|
||||||
|
// Matched an escapable character, adding a backslash on the string before the offending character
|
||||||
|
$line = substr_replace($line, '\\', strlen($match[0]), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
}
|
58
vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php
vendored
Normal file
58
vendor/league/html-to-markdown/src/Converter/PreformattedConverter.php
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class PreformattedConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$pre_content = html_entity_decode($element->getChildrenAsString());
|
||||||
|
$pre_content = str_replace(array('<pre>', '</pre>'), '', $pre_content);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checking for the code tag.
|
||||||
|
* Usually pre tags are used along with code tags. This conditional will check for already converted code tags,
|
||||||
|
* which use backticks, and if those backticks are at the beginning and at the end of the string it means
|
||||||
|
* there's no more information to convert.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$firstBacktick = strpos(trim($pre_content), '`');
|
||||||
|
$lastBacktick = strrpos(trim($pre_content), '`');
|
||||||
|
if ($firstBacktick === 0 && $lastBacktick === strlen(trim($pre_content)) - 1) {
|
||||||
|
return $pre_content . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the execution reaches this point it means it's just a pre tag, with no code tag nested
|
||||||
|
|
||||||
|
// Empty lines are a special case
|
||||||
|
if ($pre_content === '') {
|
||||||
|
return "```\n```\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalizing new lines
|
||||||
|
$pre_content = preg_replace('/\r\n|\r|\n/', "\n", $pre_content);
|
||||||
|
|
||||||
|
// Ensure there's a newline at the end
|
||||||
|
if (strrpos($pre_content, "\n") !== strlen($pre_content) - strlen("\n")) {
|
||||||
|
$pre_content .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use three backticks
|
||||||
|
return "```\n" . $pre_content . "```\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('pre');
|
||||||
|
}
|
||||||
|
}
|
48
vendor/league/html-to-markdown/src/Converter/TextConverter.php
vendored
Normal file
48
vendor/league/html-to-markdown/src/Converter/TextConverter.php
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown\Converter;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\ElementInterface;
|
||||||
|
|
||||||
|
class TextConverter implements ConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function convert(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$markdown = $element->getValue();
|
||||||
|
|
||||||
|
// Remove leftover \n at the beginning of the line
|
||||||
|
$markdown = ltrim($markdown, "\n");
|
||||||
|
|
||||||
|
// Replace sequences of invisible characters with spaces
|
||||||
|
$markdown = preg_replace('~\s+~u', ' ', $markdown);
|
||||||
|
|
||||||
|
// Escape the following characters: '*', '_', '[', ']' and '\'
|
||||||
|
if ($element->getParent() && $element->getParent()->getTagName() !== 'div') {
|
||||||
|
$markdown = preg_replace('~([*_\\[\\]\\\\])~u', '\\\\$1', $markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
$markdown = preg_replace('~^#~u', '\\\\#', $markdown);
|
||||||
|
|
||||||
|
if ($markdown === ' ') {
|
||||||
|
$next = $element->getNext();
|
||||||
|
if (!$next || $next->isBlock()) {
|
||||||
|
$markdown = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $markdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTags()
|
||||||
|
{
|
||||||
|
return array('#text');
|
||||||
|
}
|
||||||
|
}
|
257
vendor/league/html-to-markdown/src/Element.php
vendored
Normal file
257
vendor/league/html-to-markdown/src/Element.php
vendored
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
class Element implements ElementInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \DOMNode
|
||||||
|
*/
|
||||||
|
protected $node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ElementInterface|null
|
||||||
|
*/
|
||||||
|
private $nextCached;
|
||||||
|
|
||||||
|
public function __construct(\DOMNode $node)
|
||||||
|
{
|
||||||
|
$this->node = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isBlock()
|
||||||
|
{
|
||||||
|
switch ($this->getTagName()) {
|
||||||
|
case 'blockquote':
|
||||||
|
case 'body':
|
||||||
|
case 'code':
|
||||||
|
case 'div':
|
||||||
|
case 'h1':
|
||||||
|
case 'h2':
|
||||||
|
case 'h3':
|
||||||
|
case 'h4':
|
||||||
|
case 'h5':
|
||||||
|
case 'h6':
|
||||||
|
case 'hr':
|
||||||
|
case 'html':
|
||||||
|
case 'li':
|
||||||
|
case 'p':
|
||||||
|
case 'ol':
|
||||||
|
case 'ul':
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isText()
|
||||||
|
{
|
||||||
|
return $this->getTagName() === '#text';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWhitespace()
|
||||||
|
{
|
||||||
|
return $this->getTagName() === '#text' && trim($this->getValue()) === '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTagName()
|
||||||
|
{
|
||||||
|
return $this->node->nodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
return $this->node->nodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ElementInterface|null
|
||||||
|
*/
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return new static($this->node->parentNode) ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasChildren()
|
||||||
|
{
|
||||||
|
return $this->node->hasChildNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ElementInterface[]
|
||||||
|
*/
|
||||||
|
public function getChildren()
|
||||||
|
{
|
||||||
|
$ret = array();
|
||||||
|
/** @var \DOMNode $node */
|
||||||
|
foreach ($this->node->childNodes as $node) {
|
||||||
|
$ret[] = new static($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ElementInterface|null
|
||||||
|
*/
|
||||||
|
public function getNext()
|
||||||
|
{
|
||||||
|
if ($this->nextCached === null) {
|
||||||
|
$nextNode = $this->getNextNode($this->node);
|
||||||
|
if ($nextNode !== null) {
|
||||||
|
$this->nextCached = new static($nextNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->nextCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \DomNode $node
|
||||||
|
* @param bool $checkChildren
|
||||||
|
*
|
||||||
|
* @return \DomNode|null
|
||||||
|
*/
|
||||||
|
private function getNextNode($node, $checkChildren = true)
|
||||||
|
{
|
||||||
|
if ($checkChildren && $node->firstChild) {
|
||||||
|
return $node->firstChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node->nextSibling) {
|
||||||
|
return $node->nextSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node->parentNode) {
|
||||||
|
return $this->getNextNode($node->parentNode, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[]|string $tagNames
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDescendantOf($tagNames)
|
||||||
|
{
|
||||||
|
if (!is_array($tagNames)) {
|
||||||
|
$tagNames = array($tagNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($p = $this->node->parentNode; $p !== false; $p = $p->parentNode) {
|
||||||
|
if (is_null($p)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($p->nodeName, $tagNames)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $markdown
|
||||||
|
*/
|
||||||
|
public function setFinalMarkdown($markdown)
|
||||||
|
{
|
||||||
|
$markdown_node = $this->node->ownerDocument->createTextNode($markdown);
|
||||||
|
$this->node->parentNode->replaceChild($markdown_node, $this->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getChildrenAsString()
|
||||||
|
{
|
||||||
|
return $this->node->C14N();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getSiblingPosition()
|
||||||
|
{
|
||||||
|
$position = 0;
|
||||||
|
|
||||||
|
// Loop through all nodes and find the given $node
|
||||||
|
foreach ($this->getParent()->getChildren() as $current_node) {
|
||||||
|
if (!$current_node->isWhitespace()) {
|
||||||
|
$position++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Need a less-buggy way of comparing these
|
||||||
|
// Perhaps we can somehow ensure that we always have the exact same object and use === instead?
|
||||||
|
if ($this->equals($current_node)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getListItemLevel()
|
||||||
|
{
|
||||||
|
$level = 0;
|
||||||
|
$parent = $this->getParent();
|
||||||
|
|
||||||
|
while ($parent !== null && $parent->node->parentNode) {
|
||||||
|
if ($parent->getTagName() === 'li') {
|
||||||
|
$level++;
|
||||||
|
}
|
||||||
|
$parent = $parent->getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAttribute($name)
|
||||||
|
{
|
||||||
|
if ($this->node instanceof \DOMElement) {
|
||||||
|
return $this->node->getAttribute($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function equals(ElementInterface $element)
|
||||||
|
{
|
||||||
|
if ($element instanceof self) {
|
||||||
|
return $element->node === $this->node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $element === $this;
|
||||||
|
}
|
||||||
|
}
|
80
vendor/league/html-to-markdown/src/ElementInterface.php
vendored
Normal file
80
vendor/league/html-to-markdown/src/ElementInterface.php
vendored
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
interface ElementInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isText();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isWhitespace();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getTagName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ElementInterface|null
|
||||||
|
*/
|
||||||
|
public function getParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|string[] $tagNames
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDescendantOf($tagNames);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasChildren();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ElementInterface[]
|
||||||
|
*/
|
||||||
|
public function getChildren();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ElementInterface|null
|
||||||
|
*/
|
||||||
|
public function getNext();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getSiblingPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getChildrenAsString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $markdown
|
||||||
|
*/
|
||||||
|
public function setFinalMarkdown($markdown);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getAttribute($name);
|
||||||
|
}
|
104
vendor/league/html-to-markdown/src/Environment.php
vendored
Normal file
104
vendor/league/html-to-markdown/src/Environment.php
vendored
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
use League\HTMLToMarkdown\Converter\BlockquoteConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\CodeConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\CommentConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\ConverterInterface;
|
||||||
|
use League\HTMLToMarkdown\Converter\DefaultConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\DivConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\EmphasisConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\HardBreakConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\HeaderConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\HorizontalRuleConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\ImageConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\LinkConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\ListBlockConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\ListItemConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\ParagraphConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\PreformattedConverter;
|
||||||
|
use League\HTMLToMarkdown\Converter\TextConverter;
|
||||||
|
|
||||||
|
final class Environment
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Configuration
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ConverterInterface[]
|
||||||
|
*/
|
||||||
|
protected $converters = array();
|
||||||
|
|
||||||
|
public function __construct(array $config = array())
|
||||||
|
{
|
||||||
|
$this->config = new Configuration($config);
|
||||||
|
$this->addConverter(new DefaultConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Configuration
|
||||||
|
*/
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ConverterInterface $converter
|
||||||
|
*/
|
||||||
|
public function addConverter(ConverterInterface $converter)
|
||||||
|
{
|
||||||
|
if ($converter instanceof ConfigurationAwareInterface) {
|
||||||
|
$converter->setConfig($this->config);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($converter->getSupportedTags() as $tag) {
|
||||||
|
$this->converters[$tag] = $converter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $tag
|
||||||
|
*
|
||||||
|
* @return ConverterInterface
|
||||||
|
*/
|
||||||
|
public function getConverterByTag($tag)
|
||||||
|
{
|
||||||
|
if (isset($this->converters[$tag])) {
|
||||||
|
return $this->converters[$tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->converters[DefaultConverter::DEFAULT_CONVERTER];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $config
|
||||||
|
*
|
||||||
|
* @return Environment
|
||||||
|
*/
|
||||||
|
public static function createDefaultEnvironment(array $config = array())
|
||||||
|
{
|
||||||
|
$environment = new static($config);
|
||||||
|
|
||||||
|
$environment->addConverter(new BlockquoteConverter());
|
||||||
|
$environment->addConverter(new CodeConverter());
|
||||||
|
$environment->addConverter(new CommentConverter());
|
||||||
|
$environment->addConverter(new DivConverter());
|
||||||
|
$environment->addConverter(new EmphasisConverter());
|
||||||
|
$environment->addConverter(new HardBreakConverter());
|
||||||
|
$environment->addConverter(new HeaderConverter());
|
||||||
|
$environment->addConverter(new HorizontalRuleConverter());
|
||||||
|
$environment->addConverter(new ImageConverter());
|
||||||
|
$environment->addConverter(new LinkConverter());
|
||||||
|
$environment->addConverter(new ListBlockConverter());
|
||||||
|
$environment->addConverter(new ListItemConverter());
|
||||||
|
$environment->addConverter(new ParagraphConverter());
|
||||||
|
$environment->addConverter(new PreformattedConverter());
|
||||||
|
$environment->addConverter(new TextConverter());
|
||||||
|
|
||||||
|
return $environment;
|
||||||
|
}
|
||||||
|
}
|
251
vendor/league/html-to-markdown/src/HtmlConverter.php
vendored
Normal file
251
vendor/league/html-to-markdown/src/HtmlConverter.php
vendored
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class HtmlConverter
|
||||||
|
*
|
||||||
|
* A helper class to convert HTML to Markdown.
|
||||||
|
*
|
||||||
|
* @author Colin O'Dell <colinodell@gmail.com>
|
||||||
|
* @author Nick Cernis <nick@cern.is>
|
||||||
|
*
|
||||||
|
* @link https://github.com/thephpleague/html-to-markdown/ Latest version on GitHub.
|
||||||
|
*
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||||
|
*/
|
||||||
|
class HtmlConverter implements HtmlConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Environment
|
||||||
|
*/
|
||||||
|
protected $environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param Environment|array $options Environment object or configuration options
|
||||||
|
*/
|
||||||
|
public function __construct($options = array())
|
||||||
|
{
|
||||||
|
if ($options instanceof Environment) {
|
||||||
|
$this->environment = $options;
|
||||||
|
} elseif (is_array($options)) {
|
||||||
|
$defaults = array(
|
||||||
|
'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2
|
||||||
|
'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML
|
||||||
|
'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output.
|
||||||
|
'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style
|
||||||
|
'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style
|
||||||
|
'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script'
|
||||||
|
'hard_break' => false, // Set to true to turn <br> into `\n` instead of ` \n`
|
||||||
|
'list_item_style' => '-', // Set the default character for each <li> in a <ul>. Can be '-', '*', or '+'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->environment = Environment::createDefaultEnvironment($defaults);
|
||||||
|
|
||||||
|
$this->environment->getConfig()->merge($options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Environment
|
||||||
|
*/
|
||||||
|
public function getEnvironment()
|
||||||
|
{
|
||||||
|
return $this->environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Configuration
|
||||||
|
*/
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return $this->environment->getConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert
|
||||||
|
*
|
||||||
|
* @see HtmlConverter::convert
|
||||||
|
*
|
||||||
|
* @param string $html
|
||||||
|
*
|
||||||
|
* @return string The Markdown version of the html
|
||||||
|
*/
|
||||||
|
public function __invoke($html)
|
||||||
|
{
|
||||||
|
return $this->convert($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert
|
||||||
|
*
|
||||||
|
* Loads HTML and passes to getMarkdown()
|
||||||
|
*
|
||||||
|
* @param string $html
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return string The Markdown version of the html
|
||||||
|
*/
|
||||||
|
public function convert($html)
|
||||||
|
{
|
||||||
|
if (trim($html) === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$document = $this->createDOMDocument($html);
|
||||||
|
|
||||||
|
// Work on the entire DOM tree (including head and body)
|
||||||
|
if (!($root = $document->getElementsByTagName('html')->item(0))) {
|
||||||
|
throw new \InvalidArgumentException('Invalid HTML was provided');
|
||||||
|
}
|
||||||
|
|
||||||
|
$rootElement = new Element($root);
|
||||||
|
$this->convertChildren($rootElement);
|
||||||
|
|
||||||
|
// Store the now-modified DOMDocument as a string
|
||||||
|
$markdown = $document->saveHTML();
|
||||||
|
|
||||||
|
return $this->sanitize($markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $html
|
||||||
|
*
|
||||||
|
* @return \DOMDocument
|
||||||
|
*/
|
||||||
|
private function createDOMDocument($html)
|
||||||
|
{
|
||||||
|
$document = new \DOMDocument();
|
||||||
|
|
||||||
|
if ($this->getConfig()->getOption('suppress_errors')) {
|
||||||
|
// Suppress conversion errors (from http://bit.ly/pCCRSX)
|
||||||
|
libxml_use_internal_errors(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hack to load utf-8 HTML (from http://bit.ly/pVDyCt)
|
||||||
|
$document->loadHTML('<?xml encoding="UTF-8">' . $html);
|
||||||
|
$document->encoding = 'UTF-8';
|
||||||
|
|
||||||
|
if ($this->getConfig()->getOption('suppress_errors')) {
|
||||||
|
libxml_clear_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $document;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Children
|
||||||
|
*
|
||||||
|
* Recursive function to drill into the DOM and convert each node into Markdown from the inside out.
|
||||||
|
*
|
||||||
|
* Finds children of each node and convert those to #text nodes containing their Markdown equivalent,
|
||||||
|
* starting with the innermost element and working up to the outermost element.
|
||||||
|
*
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*/
|
||||||
|
private function convertChildren(ElementInterface $element)
|
||||||
|
{
|
||||||
|
// Don't convert HTML code inside <code> and <pre> blocks to Markdown - that should stay as HTML
|
||||||
|
// except if the current node is a code tag, which needs to be converted by the CodeConverter.
|
||||||
|
if ($element->isDescendantOf(array('pre', 'code')) && $element->getTagName() !== 'code') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the node has children, convert those to Markdown first
|
||||||
|
if ($element->hasChildren()) {
|
||||||
|
foreach ($element->getChildren() as $child) {
|
||||||
|
$this->convertChildren($child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that child nodes have been converted, convert the original node
|
||||||
|
$markdown = $this->convertToMarkdown($element);
|
||||||
|
|
||||||
|
// Create a DOM text node containing the Markdown equivalent of the original node
|
||||||
|
|
||||||
|
// Replace the old $node e.g. '<h3>Title</h3>' with the new $markdown_node e.g. '### Title'
|
||||||
|
$element->setFinalMarkdown($markdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to Markdown
|
||||||
|
*
|
||||||
|
* Converts an individual node into a #text node containing a string of its Markdown equivalent.
|
||||||
|
*
|
||||||
|
* Example: An <h3> node with text content of 'Title' becomes a text node with content of '### Title'
|
||||||
|
*
|
||||||
|
* @param ElementInterface $element
|
||||||
|
*
|
||||||
|
* @return string The converted HTML as Markdown
|
||||||
|
*/
|
||||||
|
protected function convertToMarkdown(ElementInterface $element)
|
||||||
|
{
|
||||||
|
$tag = $element->getTagName();
|
||||||
|
|
||||||
|
// Strip nodes named in remove_nodes
|
||||||
|
$tags_to_remove = explode(' ', $this->getConfig()->getOption('remove_nodes'));
|
||||||
|
if (in_array($tag, $tags_to_remove)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$converter = $this->environment->getConverterByTag($tag);
|
||||||
|
|
||||||
|
return $converter->convert($element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $markdown
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function sanitize($markdown)
|
||||||
|
{
|
||||||
|
$markdown = html_entity_decode($markdown, ENT_QUOTES, 'UTF-8');
|
||||||
|
$markdown = preg_replace('/<!DOCTYPE [^>]+>/', '', $markdown); // Strip doctype declaration
|
||||||
|
$markdown = trim($markdown); // Remove blank spaces at the beggining of the html
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removing unwanted tags. Tags should be added to the array in the order they are expected.
|
||||||
|
* XML, html and body opening tags should be in that order. Same case with closing tags
|
||||||
|
*/
|
||||||
|
$unwanted = array('<?xml encoding="UTF-8">', '<html>', '</html>', '<body>', '</body>', '<head>', '</head>', '
');
|
||||||
|
|
||||||
|
foreach ($unwanted as $tag) {
|
||||||
|
if (strpos($tag, '/') === false) {
|
||||||
|
// Opening tags
|
||||||
|
if (strpos($markdown, $tag) === 0) {
|
||||||
|
$markdown = substr($markdown, strlen($tag));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Closing tags
|
||||||
|
if (strpos($markdown, $tag) === strlen($markdown) - strlen($tag)) {
|
||||||
|
$markdown = substr($markdown, 0, -strlen($tag));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return trim($markdown, "\n\r\0\x0B");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass a series of key-value pairs in an array; these will be passed
|
||||||
|
* through the config and set.
|
||||||
|
* The advantage of this is that it can allow for static use (IE in Laravel).
|
||||||
|
* An example being:
|
||||||
|
*
|
||||||
|
* HtmlConverter::setOptions(['strip_tags' => true])->convert('<h1>test</h1>');
|
||||||
|
*/
|
||||||
|
public function setOptions(array $options)
|
||||||
|
{
|
||||||
|
$config = $this->getConfig();
|
||||||
|
|
||||||
|
foreach ($options as $key => $option) {
|
||||||
|
$config->setOption($key, $option);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
26
vendor/league/html-to-markdown/src/HtmlConverterInterface.php
vendored
Normal file
26
vendor/league/html-to-markdown/src/HtmlConverterInterface.php
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace League\HTMLToMarkdown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for an HTML-to-Markdown converter.
|
||||||
|
*
|
||||||
|
* @author Colin O'Dell <colinodell@gmail.com>
|
||||||
|
*
|
||||||
|
* @link https://github.com/thephpleague/html-to-markdown/ Latest version on GitHub.
|
||||||
|
*
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.php MIT
|
||||||
|
*/
|
||||||
|
interface HtmlConverterInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Convert the given $html to Markdown
|
||||||
|
*
|
||||||
|
* @param string $html
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return string The Markdown version of the html
|
||||||
|
*/
|
||||||
|
public function convert($html);
|
||||||
|
}
|
Loading…
Reference in a new issue