360 lines
13 KiB
PHP
360 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* Based on Lorem Ipsum Generator by Josh Sherman
|
|
*
|
|
* Licensed under The MIT License.
|
|
* Redistribution of these files must retain the above copyright notice.
|
|
*
|
|
* @author Josh Sherman <hello@joshtronic.com>
|
|
* @copyright Copyright 2014, 2015, 2016, 2017, 2018, 2019 Josh Sherman
|
|
* @license http://www.opensource.org/licenses/mit-license.html
|
|
* @link https://github.com/joshtronic/php-loremipsum
|
|
*/
|
|
|
|
namespace Grav\Plugin\Shortcodes;
|
|
|
|
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
|
|
|
|
class LoremShortcode extends Shortcode
|
|
{
|
|
/**
|
|
* First
|
|
*
|
|
* Whether or not we should be starting the string with "Lorem ipsum..."
|
|
*
|
|
* @access private
|
|
* @var boolean
|
|
*/
|
|
private $first = true;
|
|
/**
|
|
* Words
|
|
*
|
|
* A lorem ipsum vocabulary of sorts. Not a complete list as I'm unsure if
|
|
* a complete list exists and if so, where to get it.
|
|
*
|
|
* @access private
|
|
* @var array
|
|
*/
|
|
public $words = [
|
|
// Lorem ipsum...
|
|
'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit',
|
|
// and the rest of the vocabulary
|
|
'a', 'ac', 'accumsan', 'ad', 'aenean', 'aliquam', 'aliquet', 'ante',
|
|
'aptent', 'arcu', 'at', 'auctor', 'augue', 'bibendum', 'blandit',
|
|
'class', 'commodo', 'condimentum', 'congue', 'consequat', 'conubia',
|
|
'convallis', 'cras', 'cubilia', 'curabitur', 'curae', 'cursus',
|
|
'dapibus', 'diam', 'dictum', 'dictumst', 'dignissim', 'dis', 'donec',
|
|
'dui', 'duis', 'efficitur', 'egestas', 'eget', 'eleifend', 'elementum',
|
|
'enim', 'erat', 'eros', 'est', 'et', 'etiam', 'eu', 'euismod', 'ex',
|
|
'facilisi', 'facilisis', 'fames', 'faucibus', 'felis', 'fermentum',
|
|
'feugiat', 'finibus', 'fringilla', 'fusce', 'gravida', 'habitant',
|
|
'habitasse', 'hac', 'hendrerit', 'himenaeos', 'iaculis', 'id',
|
|
'imperdiet', 'in', 'inceptos', 'integer', 'interdum', 'justo',
|
|
'lacinia', 'lacus', 'laoreet', 'lectus', 'leo', 'libero', 'ligula',
|
|
'litora', 'lobortis', 'luctus', 'maecenas', 'magna', 'magnis',
|
|
'malesuada', 'massa', 'mattis', 'mauris', 'maximus', 'metus', 'mi',
|
|
'molestie', 'mollis', 'montes', 'morbi', 'mus', 'nam', 'nascetur',
|
|
'natoque', 'nec', 'neque', 'netus', 'nibh', 'nisi', 'nisl', 'non',
|
|
'nostra', 'nulla', 'nullam', 'nunc', 'odio', 'orci', 'ornare',
|
|
'parturient', 'pellentesque', 'penatibus', 'per', 'pharetra',
|
|
'phasellus', 'placerat', 'platea', 'porta', 'porttitor', 'posuere',
|
|
'potenti', 'praesent', 'pretium', 'primis', 'proin', 'pulvinar',
|
|
'purus', 'quam', 'quis', 'quisque', 'rhoncus', 'ridiculus', 'risus',
|
|
'rutrum', 'sagittis', 'sapien', 'scelerisque', 'sed', 'sem', 'semper',
|
|
'senectus', 'sociosqu', 'sodales', 'sollicitudin', 'suscipit',
|
|
'suspendisse', 'taciti', 'tellus', 'tempor', 'tempus', 'tincidunt',
|
|
'torquent', 'tortor', 'tristique', 'turpis', 'ullamcorper', 'ultrices',
|
|
'ultricies', 'urna', 'ut', 'varius', 'vehicula', 'vel', 'velit',
|
|
'venenatis', 'vestibulum', 'vitae', 'vivamus', 'viverra', 'volutpat',
|
|
'vulputate',
|
|
];
|
|
|
|
public function init()
|
|
{
|
|
$this->shortcode->getHandlers()->add('lorem', function(ShortcodeInterface $sc) {
|
|
$paragraphs = $sc->getParameter('p', $this->getBbCode($sc));
|
|
$paragraph_tag = $sc->getParameter('tag', 'p');
|
|
$sentences = $sc->getParameter('s');
|
|
$words = $sc->getParameter('w');
|
|
|
|
if ($words) {
|
|
return $this->words($words);
|
|
}
|
|
if ($sentences) {
|
|
return $this->sentences($sentences);
|
|
}
|
|
|
|
return $this->paragraphs($paragraphs ?? 1, $paragraph_tag);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Word
|
|
*
|
|
* Generates a single word of lorem ipsum.
|
|
*
|
|
* @access public
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @return string generated lorem ipsum word
|
|
*/
|
|
public function word($tags = false)
|
|
{
|
|
return $this->words(1, $tags);
|
|
}
|
|
/**
|
|
* Words Array
|
|
*
|
|
* Generates an array of lorem ipsum words.
|
|
*
|
|
* @access public
|
|
* @param integer $count how many words to generate
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @return array generated lorem ipsum words
|
|
*/
|
|
public function wordsArray($count = 1, $tags = false)
|
|
{
|
|
return $this->words($count, $tags, true);
|
|
}
|
|
/**
|
|
* Words
|
|
*
|
|
* Generates words of lorem ipsum.
|
|
*
|
|
* @access public
|
|
* @param integer $count how many words to generate
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @param boolean $array whether an array or a string should be returned
|
|
* @return mixed string or array of generated lorem ipsum words
|
|
*/
|
|
public function words($count = 1, $tags = false, $array = false)
|
|
{
|
|
$words = [];
|
|
$word_count = 0;
|
|
// Shuffles and appends the word list to compensate for count
|
|
// arguments that exceed the size of our vocabulary list
|
|
while ($word_count < $count) {
|
|
$shuffle = true;
|
|
while ($shuffle) {
|
|
$this->shuffle();
|
|
// Checks that the last word of the list and the first word of
|
|
// the list that's about to be appended are not the same
|
|
if (!$word_count || $words[$word_count - 1] != $this->words[0]) {
|
|
$words = array_merge($words, $this->words);
|
|
$word_count = count($words);
|
|
$shuffle = false;
|
|
}
|
|
}
|
|
}
|
|
$words = array_slice($words, 0, $count);
|
|
|
|
return $this->output($words, $tags, $array);
|
|
}
|
|
/**
|
|
* Sentence
|
|
*
|
|
* Generates a full sentence of lorem ipsum.
|
|
*
|
|
* @access public
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @return string generated lorem ipsum sentence
|
|
*/
|
|
public function sentence($tags = false)
|
|
{
|
|
return $this->sentences(1, $tags);
|
|
}
|
|
/**
|
|
* Sentences Array
|
|
*
|
|
* Generates an array of lorem ipsum sentences.
|
|
*
|
|
* @access public
|
|
* @param integer $count how many sentences to generate
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @return array generated lorem ipsum sentences
|
|
*/
|
|
public function sentencesArray($count = 1, $tags = false)
|
|
{
|
|
return $this->sentences($count, $tags, true);
|
|
}
|
|
/**
|
|
* Sentences
|
|
*
|
|
* Generates sentences of lorem ipsum.
|
|
*
|
|
* @access public
|
|
* @param integer $count how many sentences to generate
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @param boolean $array whether an array or a string should be returned
|
|
* @return mixed string or array of generated lorem ipsum sentences
|
|
*/
|
|
public function sentences($count = 1, $tags = false, $array = false)
|
|
{
|
|
$sentences = [];
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$sentences[] = $this->wordsArray($this->gauss(24.46, 5.08));
|
|
}
|
|
$this->punctuate($sentences);
|
|
|
|
return $this->output($sentences, $tags, $array);
|
|
}
|
|
/**
|
|
* Paragraph
|
|
*
|
|
* Generates a full paragraph of lorem ipsum.
|
|
*
|
|
* @access public
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @return string generated lorem ipsum paragraph
|
|
*/
|
|
public function paragraph($tags = false)
|
|
{
|
|
return $this->paragraphs(1, $tags);
|
|
}
|
|
/**
|
|
* Paragraph Array
|
|
*
|
|
* Generates an array of lorem ipsum paragraphs.
|
|
*
|
|
* @access public
|
|
* @param integer $count how many paragraphs to generate
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @return array generated lorem ipsum paragraphs
|
|
*/
|
|
public function paragraphsArray($count = 1, $tags = false)
|
|
{
|
|
return $this->paragraphs($count, $tags, true);
|
|
}
|
|
/**
|
|
* Paragraphss
|
|
*
|
|
* Generates paragraphs of lorem ipsum.
|
|
*
|
|
* @access public
|
|
* @param integer $count how many paragraphs to generate
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @param boolean $array whether an array or a string should be returned
|
|
* @return mixed string or array of generated lorem ipsum paragraphs
|
|
*/
|
|
public function paragraphs($count = 1, $tags = false, $array = false)
|
|
{
|
|
$paragraphs = [];
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$paragraphs[] = $this->sentences($this->gauss(5.8, 1.93));
|
|
}
|
|
|
|
return $this->output($paragraphs, $tags, $array, "\n\n");
|
|
}
|
|
/**
|
|
* Gaussian Distribution
|
|
*
|
|
* This is some smart kid stuff. I went ahead and combined the N(0,1) logic
|
|
* with the N(m,s) logic into this single function. Used to calculate the
|
|
* number of words in a sentence, the number of sentences in a paragraph
|
|
* and the distribution of commas in a sentence.
|
|
*
|
|
* @access private
|
|
* @param double $mean average value
|
|
* @param double $std_dev stadnard deviation
|
|
* @return double calculated distribution
|
|
*/
|
|
private function gauss($mean, $std_dev)
|
|
{
|
|
$x = mt_rand() / mt_getrandmax();
|
|
$y = mt_rand() / mt_getrandmax();
|
|
$z = sqrt(-2 * log($x)) * cos(2 * pi() * $y);
|
|
|
|
return $z * $std_dev + $mean;
|
|
}
|
|
/**
|
|
* Shuffle
|
|
*
|
|
* Shuffles the words, forcing "Lorem ipsum..." at the beginning if it is
|
|
* the first time we are generating the text.
|
|
*
|
|
* @access private
|
|
*/
|
|
private function shuffle()
|
|
{
|
|
if ($this->first) {
|
|
$this->first = array_slice($this->words, 0, 8);
|
|
$this->words = array_slice($this->words, 8);
|
|
shuffle($this->words);
|
|
$this->words = $this->first + $this->words;
|
|
$this->first = false;
|
|
} else {
|
|
shuffle($this->words);
|
|
}
|
|
}
|
|
/**
|
|
* Punctuate
|
|
*
|
|
* Applies punctuation to a sentence. This includes a period at the end,
|
|
* the injection of commas as well as capitalizing the first letter of the
|
|
* first word of the sentence.
|
|
*
|
|
* @access private
|
|
* @param array $sentences the sentences we would like to punctuate
|
|
*/
|
|
private function punctuate(&$sentences)
|
|
{
|
|
foreach ($sentences as $key => $sentence) {
|
|
$words = count($sentence);
|
|
// Only worry about commas on sentences longer than 4 words
|
|
if ($words > 4) {
|
|
$mean = log($words, 6);
|
|
$std_dev = $mean / 6;
|
|
$commas = round($this->gauss($mean, $std_dev));
|
|
for ($i = 1; $i <= $commas; $i++) {
|
|
$word = round($i * $words / ($commas + 1));
|
|
if ($word < ($words - 1) && $word > 0) {
|
|
$sentence[$word] .= ',';
|
|
}
|
|
}
|
|
}
|
|
$sentences[$key] = ucfirst(implode(' ', $sentence) . '.');
|
|
}
|
|
}
|
|
/**
|
|
* Output
|
|
*
|
|
* Does the rest of the processing of the strings. This includes wrapping
|
|
* the strings in HTML tags, handling transformations with the ability of
|
|
* back referencing and determining if the passed array should be converted
|
|
* into a string or not.
|
|
*
|
|
* @access private
|
|
* @param string|string[] $strings an array of generated strings
|
|
* @param mixed $tags string or array of HTML tags to wrap output with
|
|
* @param boolean $array whether an array or a string should be returned
|
|
* @param string $delimiter the string to use when calling implode()
|
|
* @return string|string[] string or array of generated lorem ipsum text
|
|
*/
|
|
private function output($strings, $tags, $array, $delimiter = ' ')
|
|
{
|
|
if ($tags) {
|
|
if (!is_array($tags)) {
|
|
$tags = [$tags];
|
|
} else {
|
|
// Flips the array so we can work from the inside out
|
|
$tags = array_reverse($tags);
|
|
}
|
|
foreach ($strings as $key => $string) {
|
|
foreach ($tags as $tag) {
|
|
// Detects / applies back reference
|
|
if ($tag[0] === '<') {
|
|
$string = str_replace('$1', $string, $tag);
|
|
} else {
|
|
$string = sprintf('<%1$s>%2$s</%1$s>', $tag, $string);
|
|
}
|
|
$strings[$key] = $string;
|
|
}
|
|
}
|
|
}
|
|
if (!$array) {
|
|
$strings = implode($delimiter, $strings);
|
|
}
|
|
|
|
return $strings;
|
|
}
|
|
|
|
} |