* @copyright 2009-2014 A. Grandt * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else. * @version 3.20 */ class Ncx { const _VERSION = 3.20; const MIMETYPE = "application/x-dtbncx+xml"; private $bookVersion = EPub::BOOK_VERSION_EPUB2; private $navMap = NULL; private $uid = NULL; private $meta = array(); private $docTitle = NULL; private $docAuthor = NULL; private $currentLevel = NULL; private $lastLevel = NULL; private $languageCode = "en"; private $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT; public $chapterList = array(); public $referencesTitle = "Guide"; public $referencesClass = "references"; public $referencesId = "references"; public $referencesList = array(); public $referencesName = array(); public $referencesOrder = NULL; /** * Class constructor. * * @param string $uid * @param string $docTitle * @param string $docAuthor * @param string $languageCode * @param string $writingDirection */ function __construct($uid = NULL, $docTitle = NULL, $docAuthor = NULL, $languageCode = "en", $writingDirection = EPub::DIRECTION_LEFT_TO_RIGHT) { $this->navMap = new NavMap($writingDirection); $this->currentLevel = $this->navMap; $this->setUid($uid); $this->setDocTitle($docTitle); $this->setDocAuthor($docAuthor); $this->setLanguageCode($languageCode); $this->setWritingDirection($writingDirection); } /** * Class destructor * * @return void */ function __destruct() { unset($this->bookVersion, $this->navMap, $this->uid, $this->meta); unset($this->docTitle, $this->docAuthor, $this->currentLevel, $this->lastLevel); unset($this->languageCode, $this->writingDirection, $this->chapterList, $this->referencesTitle); unset($this->referencesClass, $this->referencesId, $this->referencesList, $this->referencesName); unset($this->referencesOrder); } /** * * Enter description here ... * * @param string $bookVersion */ function setVersion($bookVersion) { $this->bookVersion = is_string($bookVersion) ? trim($bookVersion) : EPub::BOOK_VERSION_EPUB2; } /** * * @return bool TRUE if the book is set to type ePub 2 */ function isEPubVersion2() { return $this->bookVersion === EPub::BOOK_VERSION_EPUB2; } /** * * Enter description here ... * * @param string $uid */ function setUid($uid) { $this->uid = is_string($uid) ? trim($uid) : NULL; } /** * * Enter description here ... * * @param string $docTitle */ function setDocTitle($docTitle) { $this->docTitle = is_string($docTitle) ? trim($docTitle) : NULL; } /** * * Enter description here ... * * @param string $docAuthor */ function setDocAuthor($docAuthor) { $this->docAuthor = is_string($docAuthor) ? trim($docAuthor) : NULL; } /** * * Enter description here ... * * @param string $languageCode */ function setLanguageCode($languageCode) { $this->languageCode = is_string($languageCode) ? trim($languageCode) : "en"; } /** * * Enter description here ... * * @param string $writingDirection */ function setWritingDirection($writingDirection) { $this->writingDirection = is_string($writingDirection) ? trim($writingDirection) : EPub::DIRECTION_LEFT_TO_RIGHT; } /** * * Enter description here ... * * @param NavMap $navMap */ function setNavMap($navMap) { if ($navMap != NULL && is_object($navMap) && get_class($navMap) === "NavMap") { $this->navMap = $navMap; } } /** * Add one chapter level. * * Subsequent chapters will be added to this level. * * @param string $navTitle * @param string $navId * @param string $navClass * @param string $isNavHidden * @param string $writingDirection * @return NavPoint */ function subLevel($navTitle = NULL, $navId = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) { $navPoint = FALSE; if (isset($navTitle) && isset($navClass)) { $navPoint = new NavPoint($navTitle, NULL, $navId, $navClass, $isNavHidden, $writingDirection); $this->addNavPoint($navPoint); } if ($this->lastLevel !== NULL) { $this->currentLevel = $this->lastLevel; } return $navPoint; } /** * Step back one chapter level. * * Subsequent chapters will be added to this chapters parent level. */ function backLevel() { $this->lastLevel = $this->currentLevel; $this->currentLevel = $this->currentLevel->getParent(); } /** * Step back to the root level. * * Subsequent chapters will be added to the rooot NavMap. */ function rootLevel() { $this->lastLevel = $this->currentLevel; $this->currentLevel = $this->navMap; } /** * Step back to the given level. * Useful for returning to a previous level from deep within the structure. * Values below 2 will have the same effect as rootLevel() * * @param int $newLevel */ function setCurrentLevel($newLevel) { if ($newLevel <= 1) { $this->rootLevel(); } else { while ($this->currentLevel->getLevel() > $newLevel) { $this->backLevel(); } } } /** * Get current level count. * The indentation of the current structure point. * * @return current level count; */ function getCurrentLevel() { return $this->currentLevel->getLevel(); } /** * Add child NavPoints to current level. * * @param NavPoint $navPoint */ function addNavPoint($navPoint) { $this->lastLevel = $this->currentLevel->addNavPoint($navPoint); } /** * * Enter description here ... * * @return NavMap */ function getNavMap() { return $this->navMap; } /** * * Enter description here ... * * @param string $name * @param string $content */ function addMetaEntry($name, $content) { $name = is_string($name) ? trim($name) : NULL; $content = is_string($content) ? trim($content) : NULL; if ($name != NULL && $content != NULL) { $this->meta[] = array($name => $content); } } /** * * Enter description here ... * * @return string */ function finalize() { $nav = $this->navMap->finalize(); $ncx = "\n"; if ($this->isEPubVersion2()) { $ncx .= "\n"; } $ncx .= "languageCode . "\" dir=\"" . $this->writingDirection . "\">\n" . "\t\n" . "\t\tuid . "\" />\n" . "\t\tnavMap->getNavLevels() . "\" />\n" . "\t\t\n" . "\t\t\n"; if (sizeof($this->meta)) { foreach ($this->meta as $metaEntry) { list($name, $content) = each($metaEntry); $ncx .= "\t\t\n"; } } $ncx .= "\t\n\n\t\n\t\t" . $this->docTitle . "\n\t\n\n\t\n\t\t" . $this->docAuthor . "\n\t\n\n" . $nav; return $ncx . "\n"; } /** * * @param string $title * @param string $cssFileName * @return string */ function finalizeEPub3($title = "Table of Contents", $cssFileName = NULL) { $end = "\n" . "languageCode . "\" lang=\"" . $this->languageCode . "\" dir=\"" . $this->writingDirection . "\">\n" . "\t\n" . "\t\t" . $this->docTitle . "\n" . "\t\t\n"; if ($cssFileName !== NULL) { $end .= "\t\t\n"; } $end .= "\t\n" . "\t\n" . "\t\t
\n" . "\t\t\t

" . $title . "

\n" . "\t\t
\n" . $this->navMap->finalizeEPub3() . $this->finalizeEPub3Landmarks() . "\t\n" . "\n"; return $end; } /** * Build the references for the ePub 2 toc. * These are merely reference pages added to the end of the navMap though. * * @return string */ function finalizeReferences() { if (isset($this->referencesList) && sizeof($this->referencesList) > 0) { $this->rootLevel(); $this->subLevel($this->referencesTitle, $this->referencesId, $this->referencesClass); $refId = 1; while (list($item, $descriptive) = each($this->referencesOrder)) { if (array_key_exists($item, $this->referencesList)) { $name = (empty($this->referencesName[$item]) ? $descriptive : $this->referencesName[$item]); $navPoint = new NavPoint($name, $this->referencesList[$item], "ref-" . $refId++); $this->addNavPoint($navPoint); } } } } /** * Build the landmarks for the ePub 3 toc. * @return string */ function finalizeEPub3Landmarks() { $lm = ""; if (isset($this->referencesList) && sizeof($this->referencesList) > 0) { $lm = "\t\t\t\n"; } return $lm; } } /** * ePub NavMap class */ class NavMap { const _VERSION = 3.00; private $navPoints = array(); private $navLevels = 0; private $writingDirection = NULL; /** * Class constructor. * * @return void */ function __construct($writingDirection = NULL) { $this->setWritingDirection($writingDirection); } /** * Class destructor * * @return void */ function __destruct() { unset($this->navPoints, $this->navLevels, $this->writingDirection); } /** * Set the writing direction to be used for this NavPoint. * * @param string $writingDirection */ function setWritingDirection($writingDirection) { $this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL; } function getWritingDirection() { return $this->writingDirection; } /** * Add a navPoint to the root of the NavMap. * * @param NavPoint $navPoint * @return NavMap */ function addNavPoint($navPoint) { if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") { $navPoint->setParent($this); if ($navPoint->getWritingDirection() == NULL) { $navPoint->setWritingDirection($this->writingDirection); } $this->navPoints[] = $navPoint; return $navPoint; } return $this; } /** * The final max depth for the "dtb:depth" meta attribute * Only available after finalize have been called. * * @return number */ function getNavLevels() { return $this->navLevels+1; } function getLevel() { return 1; } function getParent() { return $this; } /** * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization * */ function finalize() { $playOrder = 0; $this->navLevels = 0; $nav = "\t\n"; if (sizeof($this->navPoints) > 0) { $this->navLevels++; foreach ($this->navPoints as $navPoint) { $retLevel = $navPoint->finalize($nav, $playOrder, 0); if ($retLevel > $this->navLevels) { $this->navLevels = $retLevel; } } } return $nav . "\t\n"; } /** * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization * */ function finalizeEPub3() { $playOrder = 0; $level = 0; $this->navLevels = 0; $nav = "\t\t\n"; } } /** * ePub NavPoint class */ class NavPoint { const _VERSION = 3.00; private $label = NULL; private $contentSrc = NULL; private $id = NULL; private $navClass = NULL; private $isNavHidden = FALSE; private $navPoints = array(); private $parent = NULL; /** * Class constructor. * * All three attributes are mandatory, though if ID is set to null (default) the value will be generated. * * @param string $label * @param string $contentSrc * @param string $id * @param string $navClass * @param bool $isNavHidden * @param string $writingDirection */ function __construct($label, $contentSrc = NULL, $id = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) { $this->setLabel($label); $this->setContentSrc($contentSrc); $this->setId($id); $this->setNavClass($navClass); $this->setNavHidden($isNavHidden); $this->setWritingDirection($writingDirection); } /** * Class destructor * * @return void */ function __destruct() { unset($this->label, $this->contentSrc, $this->id, $this->navClass); unset($this->isNavHidden, $this->navPoints, $this->parent); } /** * Set the Text label for the NavPoint. * * The label is mandatory. * * @param string $label */ function setLabel($label) { $this->label = is_string($label) ? trim($label) : NULL; } /** * Get the Text label for the NavPoint. * * @return string Label */ function getLabel() { return $this->label; } /** * Set the src reference for the NavPoint. * * The src is mandatory for ePub 2. * * @param string $contentSrc */ function setContentSrc($contentSrc) { $this->contentSrc = isset($contentSrc) && is_string($contentSrc) ? trim($contentSrc) : NULL; } /** * Get the src reference for the NavPoint. * * @return string content src url. */ function getContentSrc() { return $this->contentSrc; } /** * Set the parent for this NavPoint. * * @param NavPoint or NavMap $parent */ function setParent($parent) { if ($parent != NULL && is_object($parent) && (get_class($parent) === "NavPoint" || get_class($parent) === "NavMap") ) { $this->parent = $parent; } } /** * Get the parent to this NavPoint. * * @return NavPoint, or NavMap if the parent is the root. */ function getParent() { return $this->parent; } /** * Get the current level. 1 = document root. * * @return int level */ function getLevel() { return $this->parent === NULL ? 1 : $this->parent->getLevel()+1; } /** * Set the id for the NavPoint. * * The id must be unique, and is mandatory. * * @param string $id */ function setId($id) { $this->id = is_string($id) ? trim($id) : NULL; } /** * Set the class to be used for this NavPoint. * * @param string $navClass */ function setNavClass($navClass) { $this->navClass = isset($navClass) && is_string($navClass) ? trim($navClass) : NULL; } /** * Set the class to be used for this NavPoint. * * @param string $navClass */ function setNavHidden($isNavHidden) { $this->isNavHidden = $isNavHidden === TRUE; } /** * Set the writing direction to be used for this NavPoint. * * @param string $writingDirection */ function setWritingDirection($writingDirection) { $this->writingDirection = isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL; } function getWritingDirection() { return $this->writingDirection; } /** * Add child NavPoints for multi level NavMaps. * * @param NavPoint $navPoint */ function addNavPoint($navPoint) { if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") { $navPoint->setParent($this); if ($navPoint->getWritingDirection() == NULL) { $navPoint->setWritingDirection($this->writingDirection); } $this->navPoints[] = $navPoint; return $navPoint; } return $this; } /** * * Enter description here ... * * @param string $nav * @param int $playOrder * @param int $level * @return int */ function finalize(&$nav = "", &$playOrder = 0, $level = 0) { $maxLevel = $level; $levelAdjust = 0; if ($this->isNavHidden) { return $maxLevel; } if (isset($this->contentSrc)) { $playOrder++; if ($this->id == NULL) { $this->id = "navpoint-" . $playOrder; } $nav .= str_repeat("\t", $level) . "\t\tid . "\" playOrder=\"" . $playOrder . "\">\n" . str_repeat("\t", $level) . "\t\t\t\n" . str_repeat("\t", $level) . "\t\t\t\t" . $this->label . "\n" . str_repeat("\t", $level) . "\t\t\t\n" . str_repeat("\t", $level) . "\t\t\tcontentSrc . "\" />\n"; } else { $levelAdjust++; } if (sizeof($this->navPoints) > 0) { $maxLevel++; foreach ($this->navPoints as $navPoint) { $retLevel = $navPoint->finalize($nav, $playOrder, ($level+1+$levelAdjust)); if ($retLevel > $maxLevel) { $maxLevel = $retLevel; } } } if (isset($this->contentSrc)) { $nav .= str_repeat("\t", $level) . "\t\t\n"; } return $maxLevel; } /** * * Enter description here ... * * @param string $nav * @param int $playOrder * @param int $level * @return int */ function finalizeEPub3(&$nav = "", &$playOrder = 0, $level = 0, $subLevelClass = NULL, $subLevelHidden = FALSE) { $maxLevel = $level; if ($this->id == NULL) { $this->id = "navpoint-" . $playOrder; } $indent = str_repeat("\t", $level) . "\t\t\t\t"; $nav .= $indent . "
  • id . "\""; if (isset($this->writingDirection)) { $nav .= " dir=\"" . $this->writingDirection . "\""; } $nav .= ">\n"; if (isset($this->contentSrc)) { $nav .= $indent . "\tcontentSrc . "\">" . $this->label . "\n"; } else { $nav .= $indent . "\t" . $this->label . "\n"; } if (sizeof($this->navPoints) > 0) { $maxLevel++; $nav .= $indent . "\t
      navPoints as $navPoint) { $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, ($level+2), $subLevelClass, $subLevelHidden); if ($retLevel > $maxLevel) { $maxLevel = $retLevel; } } $nav .= $indent . "\t
    \n"; } $nav .= $indent . "
  • \n"; return $maxLevel; } } ?>