]>
git.immae.eu Git - github/wallabag/wallabag.git/blob - EPub.NCX.php
e5da05cdb8698f733b662dd6a0235d21a9b54a10
3 * ePub NCX file structure
5 * @author A. Grandt <php@grandt.com>
6 * @copyright 2009-2014 A. Grandt
7 * @license GNU LGPL, Attribution required for commercial implementations, requested for everything else.
11 const _VERSION
= 3.20;
13 const MIMETYPE
= "application/x-dtbncx+xml";
15 private $bookVersion = EPub
::BOOK_VERSION_EPUB2
;
17 private $navMap = NULL;
19 private $meta = array();
20 private $docTitle = NULL;
21 private $docAuthor = NULL;
23 private $currentLevel = NULL;
24 private $lastLevel = NULL;
26 private $languageCode = "en";
27 private $writingDirection = EPub
::DIRECTION_LEFT_TO_RIGHT
;
29 public $chapterList = array();
30 public $referencesTitle = "Guide";
31 public $referencesClass = "references";
32 public $referencesId = "references";
33 public $referencesList = array();
34 public $referencesName = array();
35 public $referencesOrder = NULL;
41 * @param string $docTitle
42 * @param string $docAuthor
43 * @param string $languageCode
44 * @param string $writingDirection
46 function __construct($uid = NULL, $docTitle = NULL, $docAuthor = NULL, $languageCode = "en", $writingDirection = EPub
::DIRECTION_LEFT_TO_RIGHT
) {
47 $this->navMap
= new NavMap($writingDirection);
48 $this->currentLevel
= $this->navMap
;
50 $this->setDocTitle($docTitle);
51 $this->setDocAuthor($docAuthor);
52 $this->setLanguageCode($languageCode);
53 $this->setWritingDirection($writingDirection);
61 function __destruct() {
62 unset($this->bookVersion
, $this->navMap
, $this->uid
, $this->meta
);
63 unset($this->docTitle
, $this->docAuthor
, $this->currentLevel
, $this->lastLevel
);
64 unset($this->languageCode
, $this->writingDirection
, $this->chapterList
, $this->referencesTitle
);
65 unset($this->referencesClass
, $this->referencesId
, $this->referencesList
, $this->referencesName
);
66 unset($this->referencesOrder
);
71 * Enter description here ...
73 * @param string $bookVersion
75 function setVersion($bookVersion) {
76 $this->bookVersion
= is_string($bookVersion) ? trim($bookVersion) : EPub
::BOOK_VERSION_EPUB2
;
81 * @return bool TRUE if the book is set to type ePub 2
83 function isEPubVersion2() {
84 return $this->bookVersion
=== EPub
::BOOK_VERSION_EPUB2
;
89 * Enter description here ...
93 function setUid($uid) {
94 $this->uid
= is_string($uid) ? trim($uid) : NULL;
99 * Enter description here ...
101 * @param string $docTitle
103 function setDocTitle($docTitle) {
104 $this->docTitle
= is_string($docTitle) ? trim($docTitle) : NULL;
109 * Enter description here ...
111 * @param string $docAuthor
113 function setDocAuthor($docAuthor) {
114 $this->docAuthor
= is_string($docAuthor) ? trim($docAuthor) : NULL;
119 * Enter description here ...
121 * @param string $languageCode
123 function setLanguageCode($languageCode) {
124 $this->languageCode
= is_string($languageCode) ? trim($languageCode) : "en";
129 * Enter description here ...
131 * @param string $writingDirection
133 function setWritingDirection($writingDirection) {
134 $this->writingDirection
= is_string($writingDirection) ? trim($writingDirection) : EPub
::DIRECTION_LEFT_TO_RIGHT
;
139 * Enter description here ...
141 * @param NavMap $navMap
143 function setNavMap($navMap) {
144 if ($navMap != NULL && is_object($navMap) && get_class($navMap) === "NavMap") {
145 $this->navMap
= $navMap;
150 * Add one chapter level.
152 * Subsequent chapters will be added to this level.
154 * @param string $navTitle
155 * @param string $navId
156 * @param string $navClass
157 * @param string $isNavHidden
158 * @param string $writingDirection
161 function subLevel($navTitle = NULL, $navId = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
163 if (isset($navTitle) && isset($navClass)) {
164 $navPoint = new NavPoint($navTitle, NULL, $navId, $navClass, $isNavHidden, $writingDirection);
165 $this->addNavPoint($navPoint);
167 if ($this->lastLevel
!== NULL) {
168 $this->currentLevel
= $this->lastLevel
;
174 * Step back one chapter level.
176 * Subsequent chapters will be added to this chapters parent level.
178 function backLevel() {
179 $this->lastLevel
= $this->currentLevel
;
180 $this->currentLevel
= $this->currentLevel
->getParent();
184 * Step back to the root level.
186 * Subsequent chapters will be added to the rooot NavMap.
188 function rootLevel() {
189 $this->lastLevel
= $this->currentLevel
;
190 $this->currentLevel
= $this->navMap
;
194 * Step back to the given level.
195 * Useful for returning to a previous level from deep within the structure.
196 * Values below 2 will have the same effect as rootLevel()
198 * @param int $newLevel
200 function setCurrentLevel($newLevel) {
201 if ($newLevel <= 1) {
204 while ($this->currentLevel
->getLevel() > $newLevel) {
211 * Get current level count.
212 * The indentation of the current structure point.
214 * @return current level count;
216 function getCurrentLevel() {
217 return $this->currentLevel
->getLevel();
221 * Add child NavPoints to current level.
223 * @param NavPoint $navPoint
225 function addNavPoint($navPoint) {
226 $this->lastLevel
= $this->currentLevel
->addNavPoint($navPoint);
231 * Enter description here ...
235 function getNavMap() {
236 return $this->navMap
;
241 * Enter description here ...
243 * @param string $name
244 * @param string $content
246 function addMetaEntry($name, $content) {
247 $name = is_string($name) ? trim($name) : NULL;
248 $content = is_string($content) ? trim($content) : NULL;
250 if ($name != NULL && $content != NULL) {
251 $this->meta
[] = array($name => $content);
257 * Enter description here ...
261 function finalize() {
262 $nav = $this->navMap
->finalize();
264 $ncx = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
265 if ($this->isEPubVersion2()) {
266 $ncx .= "<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\"\n"
267 . " \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n";
269 $ncx .= "<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\" xml:lang=\"" . $this->languageCode
. "\" dir=\"" . $this->writingDirection
. "\">\n"
271 . "\t\t<meta name=\"dtb:uid\" content=\"" . $this->uid
. "\" />\n"
272 . "\t\t<meta name=\"dtb:depth\" content=\"" . $this->navMap
->getNavLevels() . "\" />\n"
273 . "\t\t<meta name=\"dtb:totalPageCount\" content=\"0\" />\n"
274 . "\t\t<meta name=\"dtb:maxPageNumber\" content=\"0\" />\n";
276 if (sizeof($this->meta
)) {
277 foreach ($this->meta
as $metaEntry) {
278 list($name, $content) = each($metaEntry);
279 $ncx .= "\t\t<meta name=\"" . $name . "\" content=\"" . $content . "\" />\n";
283 $ncx .= "\t</head>\n\n\t<docTitle>\n\t\t<text>"
285 . "</text>\n\t</docTitle>\n\n\t<docAuthor>\n\t\t<text>"
287 . "</text>\n\t</docAuthor>\n\n"
290 return $ncx . "</ncx>\n";
295 * @param string $title
296 * @param string $cssFileName
299 function finalizeEPub3($title = "Table of Contents", $cssFileName = NULL) {
300 $end = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
301 . "<html xmlns=\"http://www.w3.org/1999/xhtml\"\n"
302 . " xmlns:epub=\"http://www.idpf.org/2007/ops\"\n"
303 . " xml:lang=\"" . $this->languageCode
. "\" lang=\"" . $this->languageCode
. "\" dir=\"" . $this->writingDirection
. "\">\n"
305 . "\t\t<title>" . $this->docTitle
. "</title>\n"
306 . "\t\t<meta http-equiv=\"default-style\" content=\"text/html; charset=utf-8\"/>\n";
307 if ($cssFileName !== NULL) {
308 $end .= "\t\t<link rel=\"stylesheet\" href=\"" . $cssFileName . "\" type=\"text/css\"/>\n";
310 $end .= "\t</head>\n"
311 . "\t<body epub:type=\"frontmatter toc\">\n"
313 . "\t\t\t<h1>" . $title . "</h1>\n"
315 . $this->navMap
->finalizeEPub3()
316 . $this->finalizeEPub3Landmarks()
324 * Build the references for the ePub 2 toc.
325 * These are merely reference pages added to the end of the navMap though.
329 function finalizeReferences() {
330 if (isset($this->referencesList
) && sizeof($this->referencesList
) > 0) {
332 $this->subLevel($this->referencesTitle
, $this->referencesId
, $this->referencesClass
);
334 while (list($item, $descriptive) = each($this->referencesOrder
)) {
335 if (array_key_exists($item, $this->referencesList
)) {
336 $name = (empty($this->referencesName
[$item]) ? $descriptive : $this->referencesName
[$item]);
337 $navPoint = new NavPoint($name, $this->referencesList
[$item], "ref-" . $refId++
);
338 $this->addNavPoint($navPoint);
345 * Build the landmarks for the ePub 3 toc.
348 function finalizeEPub3Landmarks() {
350 if (isset($this->referencesList
) && sizeof($this->referencesList
) > 0) {
351 $lm = "\t\t\t<nav epub:type=\"landmarks\">\n"
353 . ($this->writingDirection
=== EPub
::DIRECTION_RIGHT_TO_LEFT
? " dir=\"rtl\"" : "")
354 . ">" . $this->referencesTitle
. "</h2>\n"
358 while (list($item, $descriptive) = each($this->referencesOrder
)) {
359 if (array_key_exists($item, $this->referencesList
)) {
360 $li .= "\t\t\t\t\t<li><a epub:type=\""
362 . "\" href=\"" . $this->referencesList
[$item] . "\">"
363 . (empty($this->referencesName
[$item]) ? $descriptive : $this->referencesName
[$item])
383 const _VERSION
= 3.00;
385 private $navPoints = array();
386 private $navLevels = 0;
387 private $writingDirection = NULL;
394 function __construct($writingDirection = NULL) {
395 $this->setWritingDirection($writingDirection);
403 function __destruct() {
404 unset($this->navPoints
, $this->navLevels
, $this->writingDirection
);
408 * Set the writing direction to be used for this NavPoint.
410 * @param string $writingDirection
412 function setWritingDirection($writingDirection) {
413 $this->writingDirection
= isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
416 function getWritingDirection() {
417 return $this->writingDirection
;
421 * Add a navPoint to the root of the NavMap.
423 * @param NavPoint $navPoint
426 function addNavPoint($navPoint) {
427 if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
428 $navPoint->setParent($this);
429 if ($navPoint->getWritingDirection() == NULL) {
430 $navPoint->setWritingDirection($this->writingDirection
);
432 $this->navPoints
[] = $navPoint;
439 * The final max depth for the "dtb:depth" meta attribute
440 * Only available after finalize have been called.
444 function getNavLevels() {
445 return $this->navLevels+
1;
448 function getLevel() {
452 function getParent() {
457 * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
460 function finalize() {
462 $this->navLevels
= 0;
464 $nav = "\t<navMap>\n";
465 if (sizeof($this->navPoints
) > 0) {
467 foreach ($this->navPoints
as $navPoint) {
468 $retLevel = $navPoint->finalize($nav, $playOrder, 0);
469 if ($retLevel > $this->navLevels
) {
470 $this->navLevels
= $retLevel;
474 return $nav . "\t</navMap>\n";
478 * Finalize the navMap, the final max depth for the "dtb:depth" meta attribute can be retrieved with getNavLevels after finalization
481 function finalizeEPub3() {
484 $this->navLevels
= 0;
486 $nav = "\t\t<nav epub:type=\"toc\" id=\"toc\">\n";
488 if (sizeof($this->navPoints
) > 0) {
491 $nav .= str_repeat("\t", $level) . "\t\t\t<ol epub:type=\"list\">\n";
492 foreach ($this->navPoints
as $navPoint) {
493 $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, 0);
494 if ($retLevel > $this->navLevels
) {
495 $this->navLevels
= $retLevel;
498 $nav .= str_repeat("\t", $level) . "\t\t\t</ol>\n";
501 return $nav . "\t\t</nav>\n";
506 * ePub NavPoint class
509 const _VERSION
= 3.00;
511 private $label = NULL;
512 private $contentSrc = NULL;
514 private $navClass = NULL;
515 private $isNavHidden = FALSE;
516 private $navPoints = array();
517 private $parent = NULL;
522 * All three attributes are mandatory, though if ID is set to null (default) the value will be generated.
524 * @param string $label
525 * @param string $contentSrc
527 * @param string $navClass
528 * @param bool $isNavHidden
529 * @param string $writingDirection
531 function __construct($label, $contentSrc = NULL, $id = NULL, $navClass = NULL, $isNavHidden = FALSE, $writingDirection = NULL) {
532 $this->setLabel($label);
533 $this->setContentSrc($contentSrc);
535 $this->setNavClass($navClass);
536 $this->setNavHidden($isNavHidden);
537 $this->setWritingDirection($writingDirection);
545 function __destruct() {
546 unset($this->label
, $this->contentSrc
, $this->id
, $this->navClass
);
547 unset($this->isNavHidden
, $this->navPoints
, $this->parent
);
551 * Set the Text label for the NavPoint.
553 * The label is mandatory.
555 * @param string $label
557 function setLabel($label) {
558 $this->label
= is_string($label) ? trim($label) : NULL;
562 * Get the Text label for the NavPoint.
564 * @return string Label
566 function getLabel() {
571 * Set the src reference for the NavPoint.
573 * The src is mandatory for ePub 2.
575 * @param string $contentSrc
577 function setContentSrc($contentSrc) {
578 $this->contentSrc
= isset($contentSrc) && is_string($contentSrc) ? trim($contentSrc) : NULL;
582 * Get the src reference for the NavPoint.
584 * @return string content src url.
586 function getContentSrc() {
587 return $this->contentSrc
;
590 * Set the parent for this NavPoint.
592 * @param NavPoint or NavMap $parent
594 function setParent($parent) {
595 if ($parent != NULL && is_object($parent) &&
596 (get_class($parent) === "NavPoint" || get_class($parent) === "NavMap") ) {
597 $this->parent
= $parent;
602 * Get the parent to this NavPoint.
604 * @return NavPoint, or NavMap if the parent is the root.
606 function getParent() {
607 return $this->parent
;
611 * Get the current level. 1 = document root.
615 function getLevel() {
616 return $this->parent
=== NULL ? 1 : $this->parent
->getLevel()+
1;
620 * Set the id for the NavPoint.
622 * The id must be unique, and is mandatory.
626 function setId($id) {
627 $this->id
= is_string($id) ? trim($id) : NULL;
631 * Set the class to be used for this NavPoint.
633 * @param string $navClass
635 function setNavClass($navClass) {
636 $this->navClass
= isset($navClass) && is_string($navClass) ? trim($navClass) : NULL;
640 * Set the class to be used for this NavPoint.
642 * @param string $navClass
644 function setNavHidden($isNavHidden) {
645 $this->isNavHidden
= $isNavHidden === TRUE;
649 * Set the writing direction to be used for this NavPoint.
651 * @param string $writingDirection
653 function setWritingDirection($writingDirection) {
654 $this->writingDirection
= isset($writingDirection) && is_string($writingDirection) ? trim($writingDirection) : NULL;
657 function getWritingDirection() {
658 return $this->writingDirection
;
662 * Add child NavPoints for multi level NavMaps.
664 * @param NavPoint $navPoint
666 function addNavPoint($navPoint) {
667 if ($navPoint != NULL && is_object($navPoint) && get_class($navPoint) === "NavPoint") {
668 $navPoint->setParent($this);
669 if ($navPoint->getWritingDirection() == NULL) {
670 $navPoint->setWritingDirection($this->writingDirection
);
672 $this->navPoints
[] = $navPoint;
680 * Enter description here ...
683 * @param int $playOrder
687 function finalize(&$nav = "", &$playOrder = 0, $level = 0) {
691 if ($this->isNavHidden
) {
695 if (isset($this->contentSrc
)) {
698 if ($this->id
== NULL) {
699 $this->id
= "navpoint-" . $playOrder;
701 $nav .= str_repeat("\t", $level) . "\t\t<navPoint id=\"" . $this->id
. "\" playOrder=\"" . $playOrder . "\">\n"
702 . str_repeat("\t", $level) . "\t\t\t<navLabel>\n"
703 . str_repeat("\t", $level) . "\t\t\t\t<text>" . $this->label
. "</text>\n"
704 . str_repeat("\t", $level) . "\t\t\t</navLabel>\n"
705 . str_repeat("\t", $level) . "\t\t\t<content src=\"" . $this->contentSrc
. "\" />\n";
710 if (sizeof($this->navPoints
) > 0) {
712 foreach ($this->navPoints
as $navPoint) {
713 $retLevel = $navPoint->finalize($nav, $playOrder, ($level+
1+
$levelAdjust));
714 if ($retLevel > $maxLevel) {
715 $maxLevel = $retLevel;
720 if (isset($this->contentSrc
)) {
721 $nav .= str_repeat("\t", $level) . "\t\t</navPoint>\n";
729 * Enter description here ...
732 * @param int $playOrder
736 function finalizeEPub3(&$nav = "", &$playOrder = 0, $level = 0, $subLevelClass = NULL, $subLevelHidden = FALSE) {
739 if ($this->id
== NULL) {
740 $this->id
= "navpoint-" . $playOrder;
742 $indent = str_repeat("\t", $level) . "\t\t\t\t";
744 $nav .= $indent . "<li id=\"" . $this->id
. "\"";
745 if (isset($this->writingDirection
)) {
746 $nav .= " dir=\"" . $this->writingDirection
. "\"";
750 if (isset($this->contentSrc
)) {
751 $nav .= $indent . "\t<a href=\"" . $this->contentSrc
. "\">" . $this->label
. "</a>\n";
753 $nav .= $indent . "\t<span>" . $this->label
. "</span>\n";
756 if (sizeof($this->navPoints
) > 0) {
759 $nav .= $indent . "\t<ol epub:type=\"list\"";
760 if (isset($subLevelClass)) {
761 $nav .= " class=\"" . $subLevelClass . "\"";
763 if ($subLevelHidden) {
764 $nav .= " hidden=\"hidden\"";
768 foreach ($this->navPoints
as $navPoint) {
769 $retLevel = $navPoint->finalizeEPub3($nav, $playOrder, ($level+
2), $subLevelClass, $subLevelHidden);
770 if ($retLevel > $maxLevel) {
771 $maxLevel = $retLevel;
774 $nav .= $indent . "\t</ol>\n";
777 $nav .= $indent . "</li>\n";