Skip to content

Commit

Permalink
referenced links (url#id) broke on split chapters
Browse files Browse the repository at this point in the history
Fixed: referenced links (url#id) broke on split chapters.
Changed: Generated TOC file changed from using hardcoded spaces to
indent nested chapters, to using the CSS, defaulting to 2em per level.
The tocCss can override this by defining .level[1-n], though the default
only defines indents for levels 1-7. Reference links has their class as
class=".level1 reference"
  • Loading branch information
Grandt committed Feb 21, 2016
1 parent 09c94c6 commit 945db4d
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 11 deletions.
12 changes: 8 additions & 4 deletions REVISION.TXT
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
---------------------------------------------------------------------
Rev. 4.0.6 - 2016-02-21
* Added iBooksHelper
* Added CalibreHelper
* Added preliminary work for "Rendition" meta data
* Updated J. King's DrUUID library
* Added: iBooksHelper
* Added: CalibreHelper
* Added: preliminary work for "Rendition" meta data
* Fixed: referenced links (url#id) broke on split chapters.
* Changed: Generated TOC file changed from using hardcoded spaces to indent nested chapters, to using the CSS, defaulting to 2em per level.
* the tocCss can override this by defining .level[1-n], though the default only defines indents for levels 1-7.
* reference links has their class as class=".level1 reference"
* Updated: J. King's DrUUID library
---------------------------------------------------------------------
Rev. 4.0.5 - 2015-11-02
* Added: Support for SVG images. (experimental)
Expand Down
90 changes: 83 additions & 7 deletions src/PHPePub/Core/EPub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

use com\grandt\BinStringStatic;
use DOMDocument;
use DOMXPath;
use PHPePub\Core\Structure\Ncx;
use PHPePub\Core\Structure\NCX\NavPoint;
use PHPePub\Core\Structure\Opf;
use PHPePub\Core\Structure\OPF\DublinCore;
use PHPePub\Core\Structure\OPF\Item;
use PHPePub\Core\Structure\OPF\MarcCode;
use PHPePub\Core\Structure\OPF\MetaValue;
use PHPePub\Core\Structure\OPF\Reference;
Expand Down Expand Up @@ -266,6 +268,8 @@ function addChapter($chapterName, $fileName, $chapterData = null, $autoSplit = f

$this->chapterCount++;
$this->addFile($fileName, "chapter" . $this->chapterCount, $chapter, "application/xhtml+xml");
$this->extractIdAttributes("chapter" . $this->chapterCount, $chapter);

$this->opf->addItemRef("chapter" . $this->chapterCount);

$navPoint = new NavPoint(StringHelper::decodeHtmlEntities($chapterName), $fileName, "chapter" . $this->chapterCount);
Expand All @@ -280,8 +284,6 @@ function addChapter($chapterName, $fileName, $chapterData = null, $autoSplit = f
$partCount = 0;
$this->chapterCount++;

$this->log->logLine("addChapter: \$chapterCount: " . $this->chapterCount);

$oneChapter = each($chapter);
while ($oneChapter) {
/** @noinspection PhpUnusedLocalVariableInspection */
Expand All @@ -296,19 +298,43 @@ function addChapter($chapterName, $fileName, $chapterData = null, $autoSplit = f
$partCount++;
$partName = $name . "_" . $partCount;
$this->addFile($partName . "." . $extension, $partName, $v, "application/xhtml+xml");
$this->extractIdAttributes($partName, $v);

$this->opf->addItemRef($partName);

$oneChapter = each($chapter);
}
$partName = $name . "_1." . $extension;
$navPoint = new NavPoint(StringHelper::decodeHtmlEntities($chapterName), $partName, $partName);

$this->ncx->addNavPoint($navPoint);

$this->ncx->chapterList[$chapterName] = $navPoint;
} elseif (!isset($chapterData) && strpos($fileName, "#") > 0) {
$this->chapterCount++;
//$this->opf->addItemRef("chapter" . $this->chapterCount);

$id = preg_split("/[#]/", $fileName);
if (sizeof($id) == 2 && $this->isLogging) {

$name = preg_split('/[\.]/', $id[0]);
if (sizeof($name) > 1) {
$name = $name[0];
}

$rv = $this->opf->getItemByHref($name, true);

if ($rv != false) {
/** @var Item $item */
foreach($rv as $item) {
if ($item->hasIndexPoint($id[1])) {
$fileName = $item->getHref() . "#" . $id[1];
break;
}
}
}
}

$navPoint = new NavPoint(StringHelper::decodeHtmlEntities($chapterName), $fileName, "chapter" . $this->chapterCount);
$this->ncx->addNavPoint($navPoint);
$this->ncx->chapterList[$chapterName] = $navPoint;
Expand All @@ -325,6 +351,39 @@ function addChapter($chapterName, $fileName, $chapterData = null, $autoSplit = f
return $navPoint;
}

/**
* find all id attributes in the html document.
*
* @param string $chapterData
* @return array
*/
function findIdAttributes($chapterData) {
$xmlDoc = new DOMDocument();
@$xmlDoc->loadHTML($chapterData);

$xpath = new DomXpath($xmlDoc);

$rv = array();
// traverse all results
foreach ($xpath->query('//@id') as $rowNode) {
$rv[] = $rowNode->nodeValue;
}

return $rv;
}

/**
* @param string $partName
* @param string $chapterData
*/
public function extractIdAttributes($partName, $chapterData) {
$item = $this->opf->getItemById($partName);
$ids = $this->findIdAttributes($chapterData);
foreach ($ids as $id) {
$item->addIndexPoint($id);
}
}

/**
* Process external references from a HTML to the book. The chapter itself is not stored.
* the HTML is scanned for <link..., <style..., and <img tags.
Expand Down Expand Up @@ -1279,6 +1338,7 @@ function addReferencePage($pageName, $fileName, $pageData, $reference, $external
}

$this->addFile($fileName, "ref_" . $reference, $pageData, "application/xhtml+xml");
$this->extractIdAttributes("ref_" . $reference, $pageData);

if ($reference !== Reference::TABLE_OF_CONTENTS || !isset($this->ncx->referencesList[$reference])) {
$this->opf->addItemRef("ref_" . $reference); //, false);
Expand Down Expand Up @@ -2054,6 +2114,11 @@ private function finalizeTOC() {
$this->tocTitle = "Table of Contents";
}

$tocCssCls = "";
if (!empty($this->tocCSSClass)) {
$tocCssCls = $this->tocCSSClass . " ";
}

$tocData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";

if ($this->isEPubVersion2()) {
Expand All @@ -2066,7 +2131,16 @@ private function finalizeTOC() {
. "<head>\n<meta http-equiv=\"Default-Style\" content=\"text/html; charset=utf-8\" />\n";
}
$tocData .= $this->getViewportMetaLine();

$tocData .= "<style type=\"text/css\">\n"
. $tocCssCls. ".level1 {text-indent: 0em;}\n"
. $tocCssCls. ".level2 {text-indent: 2em;}\n"
. $tocCssCls. ".level3 {text-indent: 4em;}\n"
. $tocCssCls. ".level4 {text-indent: 6em;}\n"
. $tocCssCls. ".level5 {text-indent: 8em;}\n"
. $tocCssCls. ".level6 {text-indent: 10em;}\n"
. $tocCssCls. ".level7 {text-indent: 12em;}\n"
. $tocCssCls. ".reference {}\n"
. "</style>\n";
if (!empty($this->tocCssFileName)) {
$tocData .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"" . $this->tocCssFileName . "\" />\n";
}
Expand All @@ -2087,18 +2161,20 @@ private function finalizeTOC() {
/** @var $navPoint NavPoint */
$fileName = $navPoint->getContentSrc();
$level = $navPoint->getLevel() - 2;
$tocData .= "\t<p>" . str_repeat(" &#160; &#160; &#160;", $level) . "<a href=\"" . $fileName . "\">" . $chapterName . "</a></p>\n";
$tocData .= "\t<p class='level" . ($level+1) . "'>"
/* . str_repeat(" &#160; &#160; &#160;", $level) . */
. "<a href=\"" . $fileName . "\">" . $chapterName . "</a></p>\n";
}
} else {
if ($this->tocAddReferences === true) {
if (array_key_exists($item, $this->ncx->referencesList)) {
$tocData .= "\t<p><a href=\"" . $this->ncx->referencesList[$item] . "\">" . $descriptive . "</a></p>\n";
$tocData .= "\t<p class='level1 reference'><a href=\"" . $this->ncx->referencesList[$item] . "\">" . $descriptive . "</a></p>\n";
} else {
if ($item === "toc") {
$tocData .= "\t<p><a href=\"TOC.xhtml\">" . $this->tocTitle . "</a></p>\n";
$tocData .= "\t<p class='level1 reference'><a href=\"TOC.xhtml\">" . $this->tocTitle . "</a></p>\n";
} else {
if ($item === "cover" && $this->isCoverImageSet) {
$tocData .= "\t<p><a href=\"CoverPage.xhtml\">" . $descriptive . "</a></p>\n";
$tocData .= "\t<p class='level1 reference'><a href=\"CoverPage.xhtml\">" . $descriptive . "</a></p>\n";
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions src/PHPePub/Core/Structure/OPF/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Item {
private $fallback = null;
private $fallbackStyle = null;

private $indexPoints = array();

/**
* Class constructor.
*
Expand Down Expand Up @@ -151,4 +153,40 @@ function finalize($bookVersion = EPub::BOOK_VERSION_EPUB2) {

return $item . "/>\n";
}

/**
* @return array
*/
public function getIndexPoints() {
return $this->indexPoints;
}

/**
* @param string $indexPoint
*/
public function addIndexPoint($indexPoint) {
$this->indexPoints[] = $indexPoint;
}

/**
* @param string $indexPoint
* @return bool
*/
public function hasIndexPoint($indexPoint) {
return in_array($indexPoint, $this->indexPoints);
}

/**
* @return null
*/
public function getId() {
return $this->id;
}

/**
* @return null
*/
public function getHref() {
return $this->href;
}
}
7 changes: 7 additions & 0 deletions src/PHPePub/Core/Structure/OPF/Manifest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,11 @@ function finalize($bookVersion = EPub::BOOK_VERSION_EPUB2) {

return $manifest . "\t</manifest>\n";
}

/**
* @return array
*/
public function getItems() {
return $this->items;
}
}
39 changes: 39 additions & 0 deletions src/PHPePub/Core/Structure/Opf.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace PHPePub\Core\Structure;

use com\grandt\BinStringStatic;
use PHPePub\Core\EPub;
use PHPePub\Core\Structure\OPF\DublinCore;
use PHPePub\Core\Structure\OPF\Guide;
Expand Down Expand Up @@ -201,6 +202,44 @@ function addItem($id, $href, $mediaType, $properties = null) {
$this->manifest->addItem(new Item($id, $href, $mediaType, $properties));
}

/**
* @param string $id
*
* @return bool|Item Item if the id is found, else FALSE
*/
function getItemById($id) {
/** @var Item $item */
foreach ($this->manifest->getItems() as $item) {
if ($item->getId() == $id) {
return $item;
}
}
return false;
}

/**
* @param string $href
*
* @param bool $startsWith
* @return bool|array|Item Item if the href is found, else FALSE. If $startsWith is true, the returned object will be an array if any are found.
*/
function getItemByHref($href, $startsWith = false) {
$rv = array();

/** @var Item $item */
foreach ($this->manifest->getItems() as $item) {
if (!$startsWith && $item->getHref() == $href) {
return $item;
} elseif($startsWith && BinStringStatic::startsWith($item->getHref(), $href)) {
$rv[] = $item;
}
}
if (sizeof($rv) > 0) {
return $rv;
}
return false;
}

/**
*
* Enter description here ...
Expand Down

0 comments on commit 945db4d

Please sign in to comment.