1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
|
"""
C.4 Sectioning and Table of Contents (p174)
"""
from plasTeX import Command
#
# C.4.1 Sectioning Commands
#
class cachedproperty(object):
""" Property whose value is only calculated once and cached """
def __init__(self, func):
self._func = func
def __get__(self, obj, type=None):
if obj is None:
return self
try:
return getattr(obj, '@%s' % self._func.__name__)
except AttributeError:
result = self._func(obj)
setattr(obj, '@%s' % self._func.__name__, result)
return result
class TableOfContents(object):
"""
Table of Contents object
The table of contents object is a proxy object that limits the
depth of a table of contents entry. Each time the `tableofcontents'
attribute is accessed on the given node, the depth level is
increased. Once the depth limit has been reached, no more
table of contents entries are returned.
"""
def __init__(self, node, limit, level=1):
"""
Instantiate a table of contents object
Arguments:
node -- the node to retrieve the table of contents from
limit -- the number of levels to display
level -- the current level
"""
self._toc_node = node
self._toc_limit = limit
self._toc_level = level
def __getattribute__(self, name):
"""
Proxy all attributes to the real object except `tableofcontents'
Each nested call to the tableofcontents should limit the
depth of the items displayed.
"""
# Attributes that belong to the ToC object
if name.startswith('_toc_'):
return object.__getattribute__(self, name)
# Limit the number of ToC levels
if name in ['tableofcontents','fulltableofcontents']:
if self._toc_level < self._toc_limit:
return [type(self)(x._toc_node, self._toc_limit,
self._toc_level+1) for x in self._toc_node.fulltableofcontents]
else:
return []
# All other attribute accesses get passed on
return getattr(self._toc_node, name)
class SectionUtils(object):
""" General utilities for getting information about sections """
tocdepth = None
@cachedproperty
def footnotes(self):
output = []
for f in self.ownerDocument.userdata.get('footnotes', []):
s = f.currentSection
while s is not None and not s.filename:
s = s.currentSection
if s is self:
output.append(f)
for i, f in enumerate(output):
f.mark.attributes['num'] = i+1
return output
@cachedproperty
def subsections(self):
""" Retrieve a list of all immediate subsections of this section """
return [x for x in self if x.level < Command.ENDSECTIONS_LEVEL]
@cachedproperty
def siblings(self):
""" Retrieve a list of all sibling sections of this section """
if not self.parentNode or self.level == Command.DOCUMENT_LEVEL:
return []
return [x for x in self.parentNode.subsections if x is not self]
@cachedproperty
def tableofcontents(self):
""" Return a toble of contents object limited to toc-depth """
if self.tocdepth is not None:
tocdepth = self.tocdepth
else:
tocdepth = self.config['document']['toc-depth']
# Bail out if they don't want a ToC
if tocdepth < 1:
return []
# Don't create a ToC unless at least one subsection creates a file
if not [x for x in self.subsections if x.filename]:
return []
# Include sections that don't create files in the ToC
if self.config['document']['toc-non-files']:
return [TableOfContents(x, tocdepth) for x in self.subsections]
# Only include sections that create files in the ToC
return [TableOfContents(x, tocdepth) for x in self.subsections
if x.filename]
@cachedproperty
def fulltableofcontents(self):
""" Return a toble of contents object without limits """
# Include sections that don't create files in the ToC
if self.config['document']['toc-non-files']:
return [TableOfContents(x, 1000) for x in self.subsections]
# Only include sections that create files in the ToC
return [TableOfContents(x, 1000) for x in self.subsections
if x.filename]
@cachedproperty
def allSections(self):
""" Retrieve a list of all sections within (and including) this one """
sections = [self]
for item in self.subsections:
sections.extend(item.allSections)
return sections
@cachedproperty
def documentSections(self):
""" Retrieve a list of all sections in the document """
document = self
while document.level is not Command.DOCUMENT_LEVEL:
document = document.parentNode
if document is None:
return []
return document.allSections
@cachedproperty
def links(self):
"""
Return a dictionary containing a lot of navigation information
See http://fantasai.tripod.com/qref/Appendix/LinkTypes/ltdef.html
"""
sections = [x for x in self.documentSections if x.filename]
breadcrumbs = [self]
parent = None
if self.level > Command.DOCUMENT_LEVEL:
item = parent = self.parentNode
while item is not None and item.level > Command.DOCUMENT_LEVEL:
breadcrumbs.append(item)
item = item.parentNode
if item is not None:
breadcrumbs.append(item)
breadcrumbs.reverse()
first = top = breadcrumbs[0]
last = sections[-1]
prev = next = None
breaknext = False
for item in sections:
if item is self:
breaknext = True
continue
if breaknext:
next = item
break
prev = item
document = part = chapter = section = subsection = None
for item in breadcrumbs:
if item.level == Command.DOCUMENT_LEVEL:
document = item
elif item.level == Command.PART_LEVEL:
part = item
elif item.level == Command.CHAPTER_LEVEL:
chapter = item
elif item.level == Command.SECTION_LEVEL:
section = item
elif item.level == Command.SUBSECTION_LEVEL:
subsection = item
nav = {}
nav['home'] = top
nav['start'] = top
nav['begin'] = nav['first'] = first
nav['end'] = nav['last'] = last
nav['next'] = next
nav['previous'] = nav['prev'] = prev
nav['up'] = parent
nav['top'] = nav['origin'] = top
nav['parent'] = parent
nav['child'] = self.subsections
nav['sibling'] = self.siblings
# These aren't actually part of the spec, but I added
# them for consistency.
nav['document'] = document
nav['part'] = part
nav['chapter'] = chapter
nav['section'] = section
nav['subsection'] = subsection
nav['appendix'] = None
nav['glossary'] = None
nav['bibliography'] = None
nav['help'] = None
nav['navigator'] = top
nav['toc'] = nav['contents'] = top
nav['index'] = None
nav['search'] = None
nav['bookmark'] = None
nav['banner'] = None
nav['copyright'] = None
nav['trademark'] = None
nav['disclaimer'] = None
nav['publisher'] = None
nav['editor'] = None
nav['author'] = None
nav['made'] = None
nav['meta'] = None
nav['script'] = None
nav['stylesheet'] = []
nav['alternate'] = []
nav['translation'] = []
# Additional related entries
nav['shortcut icon'] = None
nav['breadcrumbs'] = breadcrumbs
# Get navigation info from the linkTypes
navinfo = self.ownerDocument.userdata.get('links', {})
for key, value in list(navinfo.items()):
nav[key] = value
# Get user-defined links
links = {}
for key, value in self.config['links']['links'].items():
newkey, type = key.strip().split('-',1)
if newkey not in links:
links[newkey] = {}
links[newkey][type] = value
# Set links in nav object
for key, value in list(links.items()):
if key not in list(nav.keys()) or nav[key] is None:
nav[key] = value
return nav
def digest(self, tokens):
# Absorb the tokens that belong to us
# text = []
for item in tokens:
# if item.nodeType == Command.TEXT_NODE:
# text.append(item)
# continue
if item.level <= self.level:
tokens.push(item)
break
if item.nodeType == Command.ELEMENT_NODE:
item.parentNode = self
item.digest(tokens)
# self.appendText(text, self.ownerDocument.charsubs)
self.appendChild(item)
# self.appendText(text, self.ownerDocument.charsubs)
self.paragraphs()
class StartSection(SectionUtils, Command):
blockType = True
args = '* [ toc ] title'
class part(StartSection):
level = Command.PART_LEVEL
counter = 'part'
class chapter(StartSection):
level = Command.CHAPTER_LEVEL
counter = 'chapter'
class section(StartSection):
level = Command.SECTION_LEVEL
counter = 'section'
class subsection(StartSection):
level = Command.SUBSECTION_LEVEL
counter = 'subsection'
class subsubsection(StartSection):
level = Command.SUBSUBSECTION_LEVEL
counter = 'subsubsection'
class paragraph(StartSection):
level = Command.PARAGRAPH_LEVEL
counter = 'paragraph'
class subparagraph(StartSection):
level = Command.SUBPARAGRAPH_LEVEL
counter = 'subparagraph'
class subsubparagraph(StartSection):
level = Command.SUBSUBPARAGRAPH_LEVEL
counter = 'subsubparagraph'
#
# C.4.2 The Appendix
#
class appendix(Command):
""" This needs to be implemented in the cls file """
blockType = True
#
# C.4.3 Table of Contents
#
class tableofcontents(Command):
blockType = True
class listoffigures(Command):
blockType = True
class listoftables(Command):
blockType = True
class addcontentsline(Command):
args = 'file:str level:str text'
class addtocontents(Command):
args = 'file:str text'
#
# C.4.4 Style Parameters
#
|