187 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| # -*- coding: utf-8 -*-
 | |
| # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
 | |
| 
 | |
| from __future__ import unicode_literals, division, absolute_import, print_function
 | |
| 
 | |
| from .compatibility_utils import unicode_str
 | |
| import os
 | |
| from .unipath import pathof
 | |
| 
 | |
| import re
 | |
| # note: re requites the pattern to be the exact same type as the data to be searched in python3
 | |
| # but u"" is not allowed for the pattern itself only b""
 | |
| 
 | |
| DEBUG_NAV = False
 | |
| 
 | |
| FORCE_DEFAULT_TITLE = False
 | |
| """ Set to True to force to use the default title. """
 | |
| 
 | |
| NAVIGATION_FINENAME = 'nav.xhtml'
 | |
| """ The name for the navigation document. """
 | |
| 
 | |
| DEFAULT_TITLE = 'Navigation'
 | |
| """ The default title for the navigation document. """
 | |
| 
 | |
| class NAVProcessor(object):
 | |
| 
 | |
|     def __init__(self, files):
 | |
|         self.files = files
 | |
|         self.navname = NAVIGATION_FINENAME
 | |
| 
 | |
|     def buildLandmarks(self, guidetext):
 | |
|         header = ''
 | |
|         header += '  <nav epub:type="landmarks" id="landmarks" hidden="">\n'
 | |
|         header += '    <h2>Guide</h2>\n'
 | |
|         header += '    <ol>\n'
 | |
|         element = '      <li><a epub:type="{:s}" href="{:s}">{:s}</a></li>\n'
 | |
|         footer = ''
 | |
|         footer += '    </ol>\n'
 | |
|         footer += '  </nav>\n'
 | |
| 
 | |
|         type_map = {
 | |
|             'cover' : 'cover',
 | |
|             'title-page' : 'title-page',
 | |
|             # ?: 'frontmatter',
 | |
|             'text' : 'bodymatter',
 | |
|             # ?: 'backmatter',
 | |
|             'toc' : 'toc',
 | |
|             'loi' : 'loi',
 | |
|             'lot' : 'lot',
 | |
|             'preface' : 'preface',
 | |
|             'bibliography' : 'bibliography',
 | |
|             'index' : 'index',
 | |
|             'glossary' : 'glossary',
 | |
|             'acknowledgements' : 'acknowledgements',
 | |
|             'colophon' : None,
 | |
|             'copyright-page' : None,
 | |
|             'dedication' : None,
 | |
|             'epigraph' : None,
 | |
|             'foreword' : None,
 | |
|             'notes' : None
 | |
|             }
 | |
| 
 | |
|         re_type = re.compile(r'\s+type\s*=\s*"(.*?)"', re.I)
 | |
|         re_title = re.compile(r'\s+title\s*=\s*"(.*?)"', re.I)
 | |
|         re_link = re.compile(r'\s+href\s*=\s*"(.*?)"', re.I)
 | |
|         dir_ = os.path.relpath(self.files.k8text, self.files.k8oebps).replace('\\', '/')
 | |
| 
 | |
|         data = ''
 | |
|         references = re.findall(r'<reference\s+.*?>', unicode_str(guidetext), re.I)
 | |
|         for reference in references:
 | |
|             mo_type = re_type.search(reference)
 | |
|             mo_title = re_title.search(reference)
 | |
|             mo_link = re_link.search(reference)
 | |
|             if mo_type is not None:
 | |
|                 type_ = type_map.get(mo_type.group(1), None)
 | |
|             else:
 | |
|                 type_ = None
 | |
|             if mo_title is not None:
 | |
|                 title = mo_title.group(1)
 | |
|             else:
 | |
|                 title = None
 | |
|             if mo_link is not None:
 | |
|                 link = mo_link.group(1)
 | |
|             else:
 | |
|                 link = None
 | |
| 
 | |
|             if type_ is not None and title is not None and link is not None:
 | |
|                 link = os.path.relpath(link, dir_).replace('\\', '/')
 | |
|                 data += element.format(type_, link, title)
 | |
|         if len(data) > 0:
 | |
|             return header + data + footer
 | |
|         else:
 | |
|             return ''
 | |
| 
 | |
|     def buildTOC(self, indx_data):
 | |
|         header = ''
 | |
|         header += '  <nav epub:type="toc" id="toc">\n'
 | |
|         header += '    <h1>Table of contents</h1>\n'
 | |
|         footer = '  </nav>\n'
 | |
| 
 | |
|         # recursive part
 | |
|         def recursINDX(max_lvl=0, num=0, lvl=0, start=-1, end=-1):
 | |
|             if start>len(indx_data) or end>len(indx_data):
 | |
|                 print("Warning (in buildTOC): missing INDX child entries", start, end, len(indx_data))
 | |
|                 return ''
 | |
|             if DEBUG_NAV:
 | |
|                 print("recursINDX (in buildTOC) lvl %d from %d to %d" % (lvl, start, end))
 | |
|             xhtml = ''
 | |
|             if start <= 0:
 | |
|                 start = 0
 | |
|             if end <= 0:
 | |
|                 end = len(indx_data)
 | |
|             if lvl > max_lvl:
 | |
|                 max_lvl = lvl
 | |
| 
 | |
|             indent1 = '  ' * (2 + lvl * 2)
 | |
|             indent2 = '  ' * (3 + lvl * 2)
 | |
|             xhtml += indent1 + '<ol>\n'
 | |
|             for i in range(start, end):
 | |
|                 e = indx_data[i]
 | |
|                 htmlfile = e['filename']
 | |
|                 desttag = e['idtag']
 | |
|                 text = e['text']
 | |
|                 if not e['hlvl'] == lvl:
 | |
|                     continue
 | |
|                 num += 1
 | |
|                 if desttag == '':
 | |
|                     link = htmlfile
 | |
|                 else:
 | |
|                     link = '{:s}#{:s}'.format(htmlfile, desttag)
 | |
|                 xhtml += indent2 + '<li>'
 | |
|                 entry = '<a href="{:}">{:s}</a>'.format(link, text)
 | |
|                 xhtml += entry
 | |
|                 # recurs
 | |
|                 if e['child1'] >= 0:
 | |
|                     xhtml += '\n'
 | |
|                     xhtmlrec, max_lvl, num = recursINDX(max_lvl, num, lvl + 1,
 | |
|                             e['child1'], e['childn'] + 1)
 | |
|                     xhtml += xhtmlrec
 | |
|                     xhtml += indent2
 | |
|                 # close entry
 | |
|                 xhtml += '</li>\n'
 | |
|             xhtml += indent1 + '</ol>\n'
 | |
|             return xhtml, max_lvl, num
 | |
| 
 | |
|         data, max_lvl, num = recursINDX()
 | |
|         if not len(indx_data) == num:
 | |
|             print("Warning (in buildTOC): different number of entries in NCX", len(indx_data), num)
 | |
|         return header + data + footer
 | |
| 
 | |
|     def buildNAV(self, ncx_data, guidetext, title, lang):
 | |
|         print("Building Navigation Document.")
 | |
|         if FORCE_DEFAULT_TITLE:
 | |
|             title = DEFAULT_TITLE
 | |
|         nav_header = ''
 | |
|         nav_header += '<?xml version="1.0" encoding="utf-8"?>\n<!DOCTYPE html>'
 | |
|         nav_header += '<html xmlns="http://www.w3.org/1999/xhtml"'
 | |
|         nav_header += ' xmlns:epub="http://www.idpf.org/2007/ops"'
 | |
|         nav_header += ' lang="{0:s}" xml:lang="{0:s}">\n'.format(lang)
 | |
|         nav_header += '<head>\n<title>{:s}</title>\n'.format(title)
 | |
|         nav_header += '<meta charset="UTF-8" />\n'
 | |
|         nav_header += '<style type="text/css">\n'
 | |
|         nav_header += 'nav#landmarks { display:none; }\n'
 | |
|         nav_header += '</style>\n</head>\n<body>\n'
 | |
|         nav_footer = '</body>\n</html>\n'
 | |
| 
 | |
|         landmarks =  self.buildLandmarks(guidetext)
 | |
|         toc = self.buildTOC(ncx_data)
 | |
| 
 | |
|         data = nav_header
 | |
|         data += landmarks
 | |
|         data += toc
 | |
|         data += nav_footer
 | |
|         return data
 | |
| 
 | |
|     def getNAVName(self):
 | |
|         return self.navname
 | |
| 
 | |
|     def writeNAV(self, ncx_data, guidetext, metadata):
 | |
|         # build the xhtml
 | |
|         # print("Write Navigation Document.")
 | |
|         xhtml = self.buildNAV(ncx_data, guidetext, metadata.get('Title')[0], metadata.get('Language')[0])
 | |
|         fname = os.path.join(self.files.k8text, self.navname)
 | |
|         with open(pathof(fname), 'wb') as f:
 | |
|             f.write(xhtml.encode('utf-8'))
 |