diff --git a/package_php.xml b/package_php.xml index 59c3292..a664581 100644 --- a/package_php.xml +++ b/package_php.xml @@ -44,6 +44,7 @@ Prepare CHM rendering to use the new CSS rules (Richard Quadling) Disply a message when loading an external stylesheet (Richard Quadling) Incorporate stylesheet names supplied at the command line into the CHM file (Richard Quadling) + New output format EnhancedCHM - the same as CHM but with the User Notes (Requires bzip2.exe) (Richard Quadling) @@ -67,6 +68,7 @@ + diff --git a/phpdotnet/phd/Package/PHP/CHM.php b/phpdotnet/phd/Package/PHP/CHM.php index 33b694a..44e9b48 100644 --- a/phpdotnet/phd/Package/PHP/CHM.php +++ b/phpdotnet/phd/Package/PHP/CHM.php @@ -199,7 +199,7 @@ class Package_PHP_CHM extends Package_PHP_ChunkedXHTML public function __construct() { parent::__construct(); - $this->registerFormatName("PHP-CHM"); + $this->registerFormatName("PHP-CHM"); } public function __destruct() { @@ -247,7 +247,7 @@ class Package_PHP_CHM extends Package_PHP_ChunkedXHTML $stylesheet = $this->fetchStylesheet() . PHP_EOL; } - file_put_contents($this->outputdir . "style.css", $stylesheet . 'body { padding : 3px;}'); + file_put_contents($this->outputdir . "style.css", $stylesheet . 'body {padding : 3px;}' . PHP_EOL . '#usernotes {margin-left : inherit;}' . PHP_EOL); self::headerChm(); break; @@ -402,12 +402,12 @@ res' . DIRECTORY_SEPARATOR . 'style.css $header = parent::header($id); $patterns = array( - '/(.*)(\r|\n|\r\n|\n\r)(.*)<\/head>/', // Add CSS link to + '/(.*)(\r|\n|\r\n|\n\r)(.*)<\/head>/', // Add CSS link and to . '/($2$3', + '$1 $2 $2$3', '$1 class="docs"', ); diff --git a/phpdotnet/phd/Package/PHP/EnhancedCHM.php b/phpdotnet/phd/Package/PHP/EnhancedCHM.php new file mode 100644 index 0000000..0ed2e9b --- /dev/null +++ b/phpdotnet/phd/Package/PHP/EnhancedCHM.php @@ -0,0 +1,173 @@ +registerFormatName("PHP-EnhancedCHM"); + } + + public function update($event, $val = null) { + switch($event) { + case Render::INIT: + parent::update($event, $val); + + // Get http://www.php.net/backend/notes/all.bz2 and save it. + v('Downloading usernotes.', VERBOSE_MESSAGES); + if (false === ($userNotesArchive = file_get_contents('http://www.php.net/backend/notes/all.bz2'))) { + v('Failed to download usernotes.', E_USER_ERROR); + break; + } + + // Save the usernotes. + v('Saving usernotes.', VERBOSE_MESSAGES); + if (false === file_put_contents(Config::output_dir() . 'all.bz2', $userNotesArchive)) { + v('Failed to save usernotes.', E_USER_ERROR); + break; + } + + // Decompress the usernotes. + v('Decompressing usernotes.', VERBOSE_MESSAGES); + if (false === strpos(exec('bzip2.exe -dfkv ' . Config::output_dir() . 'all.bz2 2>&1'), 'all.bz2: done')) { + v('Failed to decompress usernotes.' . PHP_EOL . implode(PHP_EOL, $output), E_USER_ERROR); + break; + } + + // Extract the usernotes and store them by page and date. + v('Preparing usernotes.', VERBOSE_MESSAGES); + + // Create usernotes directory. + $this->userNotesDir = Config::output_dir() . 'usernotes' . DIRECTORY_SEPARATOR; + if(!file_exists($this->userNotesDir) || is_file($this->userNotesDir)) { + mkdir($this->userNotesDir) or v("Can't create the usernotes directory", E_USER_ERROR); + } + + // Remove any existing files. + foreach(glob($this->userNotesDir . '*' . DIRECTORY_SEPARATOR . '*') as $sectionFile) { + unlink($sectionFile); + } + + // Decompress the 'all' file into single files - one file per sectionid. + $userNotesFile = fopen(Config::output_dir() . 'all', 'rt'); + while($userNotesFile && !feof($userNotesFile) && false !== ($userNote = fgetcsv($userNotesFile, 0, '|'))) { + // Usernote index + // 0 = Note ID + // 1 = Section ID + // 2 = Rate + // 3 = Timestamp + // 4 = User + // 5 = Note + + $sectionHash = md5($userNote[1]); + $sectionDir = $this->userNotesDir . $sectionHash[0]; + + if (!file_exists($sectionDir)) { + mkdir($sectionDir); + } + + file_put_contents($sectionDir . DIRECTORY_SEPARATOR . $sectionHash, implode('|', $userNote) . PHP_EOL, FILE_APPEND); + } + + fclose($userNotesFile); + + $this->haveNotes = true; + v('Usernotes prepared.', VERBOSE_MESSAGES); + + // Use classes rather than colors. + ini_set('highlight.comment', 'comment'); + ini_set('highlight.default', 'default'); + ini_set('highlight.keyword', 'keyword'); + ini_set('highlight.string', 'string'); + ini_set('highlight.html', 'html'); + + break; + + default: + parent::update($event, $val); + } + } + + public function footer($id) { + $footer = parent::footer($id); + + // Find usernotes file. + $idHash = md5($id); + $userNotesFile = $this->userNotesDir . $idHash[0] . DIRECTORY_SEPARATOR . $idHash; + + if (!file_exists($userNotesFile)) { + $notes = '
There are no user contributed notes for this page.
'; + } else { + $notes = ''; + + foreach(file($userNotesFile) as $userNote) { + list($noteId, $noteSection, $noteRate, $noteTimestamp, $noteUser, $noteText) = explode('|', $userNote); + + if ($noteUser) { + $noteUser = '' . htmlspecialchars($noteUser) . ''; + } + $noteDate = '' . date("d-M-Y h:i", $noteTimestamp) . ''; + $anchor = ''; + + $noteText = str_replace( + array( + ' ', + '
', + '', + "\n ", + ' ', + ' ' + ), + array( + ' ', + "
\n", + '', + "\n ", + '  ', + '  ' + ), + preg_replace( + '!((mailto:|(http|ftp|nntp|news):\/\/).*?)(\s|<|\)|"|\\\\|\'|$)!', + '\1\4', + highlight_string(trim(base64_decode($noteText)), true)) + ); + + $notes .= <<< END_NOTE + {$anchor} +
+ {$noteUser} + {$noteDate} +
+
+{$noteText} +
+
+
+
+ +END_NOTE; + } + + $notes = '
' . $notes . '
'; + } + + return <<< USER_NOTES +
+
+

User Contributed Notes

+
+{$notes} +
+{$footer} +USER_NOTES; + + } +} diff --git a/phpdotnet/phd/Package/PHP/Factory.php b/phpdotnet/phd/Package/PHP/Factory.php index 58e2120..67857b6 100644 --- a/phpdotnet/phd/Package/PHP/Factory.php +++ b/phpdotnet/phd/Package/PHP/Factory.php @@ -15,6 +15,7 @@ class Package_PHP_Factory extends Format_Factory { 'chm' => 'Package_PHP_CHM', 'tocfeed' => 'Package_PHP_TocFeed', 'epub' => 'Package_PHP_Epub', + 'enhancedchm' => 'Package_PHP_EnhancedCHM', ); public function __construct() {