1#!/usr/bin/env python 2 3r""" 4natbib 5 6TODO: 7 - compress multiple years 8 - \shortcites 9 - Indexing features 10 - Bibliography preamble 11 12""" 13 14import plasTeX, re, string 15from plasTeX import Base, Text 16 17log = plasTeX.Logging.getLogger() 18 19PackageOptions = {} 20 21def ProcessOptions(options, document): 22 """ Process package options """ 23 context = document.context 24 if options is None: 25 return 26 PackageOptions.update(options) 27 for key, value in list(options.items()): 28 if key == 'numbers': 29 bibpunct.punctuation['style'] = 'n' 30 ProcessOptions({'square':True, 'comma':True}, document) 31 elif key == 'super': 32 bibpunct.punctuation['style'] = 's' 33 bibpunct.punctuation['open'] = '' 34 bibpunct.punctuation['close'] = '' 35 elif key == 'authoryear': 36 ProcessOptions({'round':True, 'colon':True}, document) 37 elif key == 'round': 38 bibpunct.punctuation['open'] = '(' 39 bibpunct.punctuation['close'] = ')' 40 elif key == 'square': 41 bibpunct.punctuation['open'] = '[' 42 bibpunct.punctuation['close'] = ']' 43 elif key == 'angle': 44 bibpunct.punctuation['open'] = '<' 45 bibpunct.punctuation['close'] = '>' 46 elif key == 'curly': 47 bibpunct.punctuation['open'] = '{' 48 bibpunct.punctuation['close'] = '}' 49 elif key == 'comma': 50 bibpunct.punctuation['sep'] = ',' 51 elif key == 'colon': 52 bibpunct.punctuation['sep'] = ';' 53 elif key == 'sectionbib': 54 Base.bibliography.level = Base.section.level 55 elif key == 'sort': 56 pass 57 elif key in ['sort&compress','sortandcompress']: 58 pass 59 elif key == 'longnamesfirst': 60 pass 61 elif key == 'nonamebreak': 62 pass 63 64class bibliography(Base.bibliography): 65 66 class setcounter(Base.Command): 67 # Added so that setcounters in the aux file don't mess counters up 68 args = 'name:nox num:nox' 69 70 def loadBibliographyFile(self, tex): 71 doc = self.ownerDocument 72 # Clear out any bib info from the standard package. 73 # We have to get our info from the aux file. 74 doc.userdata.setPath('bibliography/bibcites', {}) 75 self.ownerDocument.context.push(self) 76 self.ownerDocument.context['setcounter'] = self.setcounter 77 tex.loadAuxiliaryFile() 78 self.ownerDocument.context.pop(self) 79 Base.bibliography.loadBibliographyFile(self, tex) 80 81class bibstyle(Base.Command): 82 args = 'style:str' 83 84class citestyle(Base.Command): 85 args = 'style:str' 86 87 styles = { 88 'plain' : [', ','[',']',',','n','',','], 89 'plainnat':[', ','[',']',',','a',',',','], 90 'chicago': [', ','(',')',';','a',',',','], 91 'chicago': [', ','(',')',';','a',',',','], 92 'named' : [', ','[',']',';','a',',',','], 93 'agu' : [', ','[',']',';','a',',',', '], 94 'egs' : [', ','(',')',';','a',',',','], 95 'agsm' : [', ','(',')',';','a','',','], 96 'kluwer' : [', ','(',')',';','a','',','], 97 'dcu' : [', ','(',')',';','a',';',','], 98 'aa' : [', ','(',')',';','a','',','], 99 'pass' : [', ','(',')',';','a',',',','], 100 'anngeo' : [', ','(',')',';','a',',',','], 101 'nlinproc':[', ','(',')',';','a',',',','], 102 'cospar' : [', ','/','/',',','n','',''], 103 'esa' : [', ','(Ref. ',')',',','n','',''], 104 'nature' : [', ','','',',','s','',','], 105 } 106 107 def invoke(self, tex): 108 res = Base.Command.invoke(self, tex) 109 try: 110 s = self.styles[self.attributes['style']] 111 except KeyError: 112 # log.warning('Could not find bibstyle: "%s"', 113 # self.attributes['style']) 114 return res 115 p = bibpunct.punctuation 116 for i, opt in enumerate(['post','open','close','sep','style','dates','years']): 117 p[opt] = s[i] 118 return res 119 120class bstyleoption(Text): 121 """ Option that can only be overridden by package options, 122 citestyle, or bibpunct """ 123 124class bibliographystyle(citestyle): 125 def invoke(self, tex): 126 res = Base.Command.invoke(self, tex) 127 try: 128 s = self.styles[self.attributes['style']] 129 except KeyError: 130 # log.warning('Could not find bibstyle: "%s"', 131 # self.attributes['style']) 132 return res 133 p = bibpunct.punctuation 134 for i, opt in enumerate(['post','open','close','sep','style','dates','years']): 135 if isinstance(p[opt], bstyleoption): 136 p[opt] = s[i] 137 return res 138 139class bibpunct(Base.Command): 140 """ Set up punctuation of citations """ 141 args = '[ post:str ] open:str close:str sep:str ' + \ 142 'style:str dates:str years:str' 143 punctuation = {'post': bstyleoption(', '), 144 'open': bstyleoption('('), 145 'close':bstyleoption(')'), 146 'sep': bstyleoption(';'), 147 'style':bstyleoption('a'), 148 'dates':bstyleoption(','), 149 'years':bstyleoption(',')} 150 def invoke(self, tex): 151 res = Base.Command.invoke(self, tex) 152 for key, value in list(self.attributes.items()): 153 if value is None: 154 continue 155 elif type(value) == str or type(value) == str: 156 bibpunct.punctuation[key] = value 157 else: 158 bibpunct.punctuation[key] = value.textContent 159 return res 160 161class bibcite(Base.Command): 162 """ Auxiliary file information """ 163 args = 'key:str info' 164 165 def invoke(self, tex): 166 Base.Command.invoke(self, tex) 167 value, year, author, fullauthor = list(self.attributes['info']) 168 value.attributes['year'] = year 169 value.attributes['author'] = author 170 if not fullauthor.textContent.strip(): 171 value.attributes['fullauthor'] = author 172 else: 173 value.attributes['fullauthor'] = fullauthor 174 doc = self.ownerDocument 175 bibcites = doc.userdata.getPath('bibliography/bibcites', {}) 176 bibcites[self.attributes['key']] = value 177 doc.userdata.setPath('bibliography/bibcites', bibcites) 178 179class thebibliography(Base.thebibliography): 180 181 class bibitem(Base.thebibliography.bibitem): 182 183 @property 184 def bibcite(self): 185 try: 186 doc = self.ownerDocument 187 return doc.userdata.getPath('bibliography/bibcites', {})[self.attributes['key']] 188 except KeyError as msg: 189 pass 190 # We don't have a citation that matches, fill the fields 191 # with dummy data 192 value = self.ownerDocument.createElement('citation') 193 value.parentNode = self 194 value.append('??') 195 for item in ['year','author','fullauthor']: 196 obj = self.ownerDocument.createDocumentFragment() 197 obj.parentNode = value 198 obj.append('??') 199 value.attributes[item] = obj 200 return value 201 202 def ref(): 203 def fset(self, value): 204 pass 205 def fget(self): 206 return self.bibcite.textContent 207 return locals() 208 ref = property(**ref()) 209 210class harvarditem(thebibliography.bibitem): 211 args = '[ abbrlabel ] label year key:str' 212 213class NatBibCite(Base.cite): 214 """ Base class for all natbib-style cite commands """ 215 args = '* [ text ] [ text2 ] bibkeys:list:str' 216 217 class Connector(str): 218 pass 219 220 @property 221 def bibitems(self): 222 items = [] 223 opts = PackageOptions 224 doc = self.ownerDocument 225 b = doc.userdata.getPath('bibliography/bibitems', {}) 226 for key in self.attributes['bibkeys']: 227 if key in b: 228 items.append(b[key]) 229 if bibpunct.punctuation['style'] in 'ns' and \ 230 ('sort' in opts or 'sort&compress' in opts or 'sortandcompress' in opts): 231 items.sort(lambda x, y: int(x.ref) - int(y.ref)) 232 if 'sort&compress' in opts or 'sortandcompress' in opts: 233 items = self.compressRange(items) 234 return items 235 236 def compressRange(self, items): 237 """ Compress ranges of numbers """ 238 idx, idxdict = [], {} 239 for i, value in enumerate(items): 240 idx.append(int(value.ref)) 241 idxdict[int(value.ref)] = value 242 output = [] 243 for i, value in enumerate(idx): 244 if i == 0: 245 output.append(' ') 246 output.append(value) 247 elif idx[i-1] == (value-1): 248 output.append('-') 249 output.append(value) 250 else: 251 output.append(' ') 252 output.append(value) 253 output.append(' ') 254 output = ''.join([str(x) for x in output]) 255 output = re.sub(r'( \d+)-(\d+ )', r'\1 \2', output) 256 while re.search(r'-\d+-', output): 257 output = re.sub(r'-\d+-', r'-', output) 258 output = [x for x in re.split(r'([ -])', output) if x.strip()] 259 for i, value in enumerate(output): 260 if value in string.digits: 261 output[i] = idxdict[int(value)] 262 else: 263 output[i] = self.Connector(value) 264 return output 265 266 def isConnector(self, value): 267 return isinstance(value, self.Connector) 268 269 @property 270 def prenote(self): 271 """ Text that comes before the citation """ 272 a = self.attributes 273 if a.get('text2') is not None and a.get('text') is not None: 274 if not a.get('text').textContent.strip(): 275 return '' 276 out = self.ownerDocument.createElement('bgroup') 277 out.extend(a['text']) 278 out.append(' ') 279 return out 280 return '' 281 282 @property 283 def postnote(self): 284 """ Text that comes after the citation """ 285 a = self.attributes 286 if a.get('text2') is not None and a.get('text') is not None: 287 if not a.get('text2').textContent.strip(): 288 return '' 289 out = self.ownerDocument.createElement('bgroup') 290 out.append(bibpunct.punctuation['post']) 291 out.extend(a['text2']) 292 return out 293 elif a.get('text') is not None: 294 if not a.get('text').textContent.strip(): 295 return '' 296 out = self.ownerDocument.createElement('bgroup') 297 out.append(bibpunct.punctuation['post']) 298 out.extend(a['text']) 299 return out 300 return '' 301 302 @property 303 def separator(self): 304 """ Separator for multiple items """ 305 return bibpunct.punctuation['sep'] 306 307 @property 308 def dates(self): 309 """ Separator between author and dates """ 310 return bibpunct.punctuation['dates'] 311 312 @property 313 def years(self): 314 """ Separator for multiple years """ 315 return bibpunct.punctuation['years'] 316 317 def selectAuthorField(self, key, full=False): 318 """ Determine if author should be a full name or shortened """ 319 if full or self.attributes.get('*modifier*'): 320 return 'fullauthor' 321 doc = self.ownerDocument 322 # longnamesfirst means that only the first reference 323 # gets the full length name, the rest use short names. 324 cited = doc.userdata.getPath('bibliography/cited', []) 325 if 'longnamesfirst' in PackageOptions and key not in cited: 326 full = True 327 cited.append(key) 328 doc.userdata.setPath('bibliography/cited', cited) 329 if full: 330 return 'fullauthor' 331 return 'author' 332 333 def isNumeric(self): 334 return bibpunct.punctuation['style'] in ['n','s'] 335 336 def isSuperScript(self): 337 return bibpunct.punctuation['style'] == 's' 338 339 def citeValue(self, item, text=None): 340 """ Return cite value based on current style """ 341 b = self.ownerDocument.createElement('bibliographyref') 342 b.idref['bibitem'] = item 343 if text is not None: 344 b.append(text) 345 elif bibpunct.punctuation['style'] in ['n','s']: 346 b.append(item.bibcite) 347 else: 348 b.append(item.bibcite.attributes['year']) 349 return b 350 351 def capitalize(self, item): 352 """ Capitalize the first text node """ 353 item = item.cloneNode(True) 354 textnodes = [x for x in item.allChildNodes 355 if x.nodeType == self.TEXT_NODE] 356 if not textnodes: 357 return item 358 node = textnodes.pop(0) 359 node.parentNode.replaceChild(node.cloneNode(True).capitalize() ,node) 360 return item 361 362# class citep(NatBibCite): 363 364# def numcitation(self): 365# """ Numeric style citations """ 366# res = [] 367# res.append(bibpunct.punctuation['open']) 368# for i, item in enumerate(self.bibitems): 369# frag = self.ownerDocument.createDocumentFragment() 370# frag.append(item.ref) 371# frag.idref = item 372# res.append(frag) 373# res.append(bibpunct.punctuation['sep']) 374# res.pop() 375# res.append(bibpunct.punctuation['close']) 376# return res 377 378# def citation(self): 379# if bibpunct.punctuation['style'] == 'n': 380# return self.numcitation() 381# elif bibpunct.punctuation['style'] == 's': 382# return self.numcitation() 383 384# res = [] 385# res.append(bibpunct.punctuation['open'] + self.prenote) 386# prevauthor = None 387# prevyear = None 388# duplicateyears = 0 389# previtem = None 390# for i, item in enumerate(self.bibitems): 391# currentauthor = item.citeauthor().textContent 392# currentyear = item.citeyear().textContent 393 394# # Previous author and year are the same 395# if prevauthor == currentauthor and prevyear == currentyear: 396# res.pop() 397# # This is the first duplicate 398# if duplicateyears == 0: 399# # Make a reference that points to the same item as 400# # the first citation in this set. This will make 401# # hyperlinked output prettier since the 'a' will 402# # be linked to the same place as the reference that 403# # we just put out. 404# res.append('') 405# frag = self.ownerDocument.createDocumentFragment() 406# frag.append('a') 407# frag.idref = previtem 408# res.append(frag) 409# res.append(bibpunct.punctuation['years']) 410# else: 411# res.append(bibpunct.punctuation['years']) 412# # Create a new fragment with b,c,d... in it 413# frag = self.ownerDocument.createDocumentFragment() 414# frag.append(chr(duplicateyears+ord('b'))) 415# frag.idref = item 416# res.append(frag) 417# res.append(bibpunct.punctuation['sep']+' ') 418# duplicateyears += 1 419 420# # Previous author is the same 421# elif prevauthor == currentauthor: 422# duplicateyears = 0 423# res.pop() 424# res.append(bibpunct.punctuation['years']+' ') 425# res.append(item.citeyear()) 426# res.append(bibpunct.punctuation['sep']+' ') 427 428# # Nothing about the previous citation is the same 429# else: 430# doc = self.ownerDocument 431# cited = doc.userdata.getPath('bibliography/cited', []) 432# duplicateyears = 0 433# if 'longnamesfirst' in PackageOptions and \ 434# item.attributes['key'] not in cited: 435# cited.append(item.attributes['key']) 436# doc.userdata.setPath('bibliography/cited', cited) 437# res.append(item.citealp(full=True)) 438# else: 439# res.append(item.citealp()) 440# res.append(bibpunct.punctuation['sep']+' ') 441 442# prevauthor = currentauthor 443# prevyear = currentyear 444# previtem = item 445 446# res.pop() 447# res.append(self.postnote + bibpunct.punctuation['close']) 448# return res 449 450class citet(NatBibCite): 451 452 def citation(self, full=False, capitalize=False, text=None): 453 """ Jones et al. (1990) """ 454 if text is None and self.isNumeric(): 455 return self.numcitation() 456 res = self.ownerDocument.createDocumentFragment() 457 i = 0 458 sameauthor = prevauthor = None 459 for i, item in enumerate(self.bibitems): 460 if text is None: 461 if not item.bibcite.attributes: 462 continue 463 fullauthor = item.bibcite.attributes['fullauthor'].textContent 464 sameauthor = (prevauthor == fullauthor) 465 prevauthor = fullauthor 466 # Author, only print author if it wasn't equal to the last author 467 if sameauthor: 468 # Pop punctuation from previous year 469 res.pop() 470 res.pop() 471 # Add year separator 472 res.append(self.years+' ') 473 else: 474 author = self.selectAuthorField(item.attributes['key'], full=full) 475 if i == 0 and capitalize: 476 res.extend(self.capitalize(item.bibcite.attributes[author])) 477 else: 478 res.extend(item.bibcite.attributes[author]) 479 res.append(' ') 480 res.append(bibpunct.punctuation['open']) 481 # Prenote 482 res.append(self.prenote) 483 # Year or text 484 res.append(self.citeValue(item, text=text)) 485 # Separator, postnote, and closing punctuation 486 if i < (len(self.bibitems)-1): 487 if text is None: 488 res.append(bibpunct.punctuation['close']) 489 res.append(self.separator+' ') 490 else: 491 res.append(self.postnote) 492 if text is None: 493 res.append(bibpunct.punctuation['close']) 494 return res 495 496 def numcitation(self, full=False, capitalize=False): 497 """ (1, 2) """ 498 element = self.ownerDocument.createElement 499 orig = res = self.ownerDocument.createDocumentFragment() 500 if self.isSuperScript(): 501 group = element('bgroup') 502 orig.append(group) 503 res = element('active::^') 504 group.append(res) 505 i = 0 506 res.append(self.prenote) 507 res.append(bibpunct.punctuation['open']) 508 for i, item in enumerate(self.bibitems): 509 if self.isConnector(item): 510 res.pop() 511 res.append('-') 512 continue 513 res.append(self.citeValue(item)) 514 if i < (len(self.bibitems)-1): 515 res.append(self.separator+' ') 516 res.append(bibpunct.punctuation['close']) 517 res.append(self.postnote) 518 return orig 519 520class citetfull(citet): 521 522 def citation(self): 523 """ Jones, Baker, and Williams (1990) """ 524 return citet.citation(self, full=True) 525 526class Citet(citet): 527 528 def citation(self): 529 return citet.citation(self, capitalize=True) 530 531class citep(NatBibCite): 532 533 def citation(self, full=False, capitalize=False, text=None): 534 """ (Jones et al., 1990) """ 535 if text is None and self.isNumeric(): 536 return self.numcitation() 537 res = self.ownerDocument.createDocumentFragment() 538 res.append(bibpunct.punctuation['open']) 539 res.append(self.prenote) 540 i = 0 541 sameauthor = prevauthor = None 542 for i, item in enumerate(self.bibitems): 543 if text is None: 544 if item.bibcite.attributes is None: 545 continue 546 fullauthor = item.bibcite.attributes['fullauthor'].textContent 547 sameauthor = (prevauthor == fullauthor) 548 prevauthor = fullauthor 549 # Author, only print author if it wasn't equal to the last author 550 if sameauthor: 551 res.pop() 552 res.append(self.years+' ') 553 else: 554 author = self.selectAuthorField(item.attributes['key'], full=full) 555 if i == 0 and capitalize: 556 res.extend(self.capitalize(item.bibcite.attributes[author])) 557 else: 558 res.extend(item.bibcite.attributes[author]) 559 res.append(self.dates+' ') 560 res.append(self.citeValue(item, text=text)) 561 if i < (len(self.bibitems)-1): 562 res.append(self.separator+' ') 563 else: 564 res.append(self.postnote) 565 res.append(bibpunct.punctuation['close']) 566 return res 567 568 def numcitation(self): 569 """ (1, 2) """ 570 element = self.ownerDocument.createElement 571 orig = res = self.ownerDocument.createDocumentFragment() 572 if self.isSuperScript(): 573 group = element('bgroup') 574 orig.append(group) 575 res = element('active::^') 576 group.append(res) 577 res.append(bibpunct.punctuation['open']) 578 res.append(self.prenote) 579 i = 0 580 for i, item in enumerate(self.bibitems): 581 if self.isConnector(item): 582 res.pop() 583 res.append('-') 584 continue 585 res.append(self.citeValue(item)) 586 if i < (len(self.bibitems)-1): 587 res.append(self.separator+' ') 588 else: 589 res.append(self.postnote) 590 res.append(bibpunct.punctuation['close']) 591 return orig 592 593class cite(citep, citet): 594 595 def citation(self, full=False, capitalize=False): 596 if self.prenote or self.postnote: 597 return citep.citation(self, full=full, capitalize=capitalize) 598 return citet.citation(self, full=full, capitalize=capitalize) 599 600class Cite(cite): 601 602 def citation(self): 603 return cite.citation(self, capitalize=True) 604 605class citepfull(citep): 606 607 def citation(self): 608 """ (Jones, Baker, and Williams, 1990) """ 609 return citep.citation(self, full=True) 610 611class Citep(citep): 612 613 def citation(self): 614 return citep.citation(self, capitalize=True) 615 616class citealt(NatBibCite): 617 618 def citation(self, full=False, capitalize=False): 619 """ Jones et al. 1990 """ 620 if self.isNumeric(): 621 return self.numcitation() 622 res = self.ownerDocument.createDocumentFragment() 623 i = 0 624 prevauthor = sameauthor = None 625 for i, item in enumerate(self.bibitems): 626 if not item.bibcite.attributes: 627 fullauthor = '???' 628 else: 629 fullauthor = item.bibcite.attributes['fullauthor'].textContent 630 sameauthor = (prevauthor == fullauthor) 631 prevauthor = fullauthor 632 # Author, only print author if it wasn't equal to the last author 633 if sameauthor: 634 res.pop() 635 res.append(self.years+' ') 636 else: 637 author = self.selectAuthorField(item.attributes['key'], full=full) 638 if not item.bibcite.attributes: 639 res.extend('???') 640 elif i == 0 and capitalize: 641 res.extend(self.capitalize(item.bibcite.attributes[author])) 642 else: 643 res.extend(item.bibcite.attributes[author]) 644 res.append(' ') 645 res.append(self.prenote) 646 res.append(self.citeValue(item)) 647 if i < (len(self.bibitems)-1): 648 res.append(self.separator+' ') 649 else: 650 res.append(self.postnote) 651 return res 652 653 def numcitation(self): 654 """ 1, 2 """ 655 element = self.ownerDocument.createElement 656 orig = res = self.ownerDocument.createDocumentFragment() 657 if self.isSuperScript(): 658 group = element('bgroup') 659 orig.append(group) 660 res = element('active::^') 661 group.append(res) 662 i = 0 663 res.append(self.prenote) 664 for i, item in enumerate(self.bibitems): 665 if self.isConnector(item): 666 res.pop() 667 res.append('-') 668 continue 669 res.append(self.citeValue(item)) 670 if i < (len(self.bibitems)-1): 671 res.append(self.separator+' ') 672 else: 673 res.append(self.postnote) 674 return orig 675 676class citealtfull(citealt): 677 678 def citation(self): 679 """ Jones, Baker, and Williams 1990 """ 680 return citealt.citation(self, full=True) 681 682class Citealt(citealt): 683 684 def citation(self): 685 return citealt.citation(self, capitalize=True) 686 687class citealp(NatBibCite): 688 689 def citation(self, full=False, capitalize=False): 690 """ Jones et al., 1990 """ 691 if self.isNumeric(): 692 return self.numcitation() 693 res = self.ownerDocument.createDocumentFragment() 694 res.append(self.prenote) 695 i = 0 696 prevauthor = sameauthor = None 697 for i, item in enumerate(self.bibitems): 698 if not item.bibcite.attributes: 699 fullauthor = '???' 700 else: 701 fullauthor = item.bibcite.attributes['fullauthor'].textContent 702 sameauthor = (prevauthor == fullauthor) 703 prevauthor = fullauthor 704 # Author, only print author if it wasn't equal to the last author 705 if sameauthor: 706 res.pop() 707 res.append(self.years+' ') 708 else: 709 author = self.selectAuthorField(item.attributes['key'], full=full) 710 if not item.bibcite.attributes: 711 res.extend('???') 712 elif i == 0 and capitalize: 713 res.extend(self.capitalize(item.bibcite.attributes[author])) 714 else: 715 res.extend(item.bibcite.attributes[author]) 716 res.append(self.separator+' ') 717 res.append(self.citeValue(item)) 718 if i < (len(self.bibitems)-1): 719 res.append(self.separator+' ') 720 else: 721 res.append(self.postnote) 722 return res 723 724 def numcitation(self): 725 """ 1, 2 """ 726 element = self.ownerDocument.createElement 727 orig = res = self.ownerDocument.createDocumentFragment() 728 if self.isSuperScript(): 729 group = element('bgroup') 730 orig.append(group) 731 res = element('active::^') 732 group.append(res) 733 res.append(self.prenote) 734 i = 0 735 for i, item in enumerate(self.bibitems): 736 if self.isConnector(item): 737 res.pop() 738 res.append('-') 739 continue 740 res.append(self.citeValue(item)) 741 if i < (len(self.bibitems)-1): 742 res.append(self.separator+' ') 743 res.append(self.postnote) 744 return orig 745 746class citealpfull(citealp): 747 748 def citation(self): 749 """ Jones, Baker, and Williams, 1990 """ 750 return citealp.citation(self, full=True) 751 752class Citealp(citealp): 753 754 def citation(self): 755 return citealp.citation(self, capitalize=True) 756 757class citeauthor(NatBibCite): 758 759 def citation(self, full=False, capitalize=False): 760 """ Jones et al. """ 761 if self.isNumeric(): 762 return 763 res = self.ownerDocument.createDocumentFragment() 764 #res.append(self.prenote) 765 i = 0 766 for i, item in enumerate(self.bibitems): 767 author = self.selectAuthorField(item.attributes['key'], full=full) 768 b = self.ownerDocument.createElement('bibliographyref') 769 b.idref['bibitem'] = item 770 if not item.bibcite.attributes: 771 b.append('???') 772 elif i == 0 and capitalize: 773 b.append(self.capitalize(item.bibcite.attributes[author])) 774 else: 775 b.append(item.bibcite.attributes[author]) 776 res.append(b) 777 if i < (len(self.bibitems)-1): 778 res.append(self.separator+' ') 779 else: 780 res.append(self.postnote) 781 return res 782 783class citefullauthor(citeauthor): 784 785 def citation(self): 786 """ Jones, Baker, and Williams """ 787 return citeauthor.citation(self, full=True) 788 789class Citeauthor(citeauthor): 790 791 def citation(self): 792 return citeauthor.citation(self, capitalize=True) 793 794class citeyear(NatBibCite): 795 796 def citation(self): 797 """ 1990 """ 798 if self.isNumeric(): 799 return 800 res = self.ownerDocument.createDocumentFragment() 801 #res.append(self.prenote) 802 i = 0 803 for i, item in enumerate(self.bibitems): 804 b = self.ownerDocument.createElement('bibliographyref') 805 b.idref['bibitem'] = item 806 if not item.bibcite.attributes: 807 b.append('???') 808 else: 809 b.append(item.bibcite.attributes['year']) 810 res.append(b) 811 if i < (len(self.bibitems)-1): 812 res.append(self.separator+' ') 813 else: 814 res.append(self.postnote) 815 return res 816 817class citeyearpar(NatBibCite): 818 819 def citation(self): 820 """ (1990) """ 821 if self.isNumeric(): 822 return 823 res = self.ownerDocument.createDocumentFragment() 824 res.append(bibpunct.punctuation['open']) 825 res.append(self.prenote) 826 i = 0 827 for i, item in enumerate(self.bibitems): 828 b = self.ownerDocument.createElement('bibliographyref') 829 b.idref['bibitem'] = item 830 if not item.bibcite.attributes: 831 b.append('???') 832 else: 833 b.append(item.bibcite.attributes['year']) 834 res.append(b) 835 if i < (len(self.bibitems)-1): 836 res.append(self.separator+' ') 837 else: 838 res.append(self.postnote) 839 res.append(bibpunct.punctuation['close']) 840 return res 841 842class citetext(Base.Command): 843 args = 'self' 844 def digest(self, tokens): 845 self.insert(0, bibpunct.punctuation['open']) 846 self.append(bibpunct.punctuation['close']) 847 848class defcitealias(Base.Command): 849 args = 'key:str text' 850 aliases = {} 851 def invoke(self, tex): 852 res = Base.Command.invoke(self, tex) 853 defcitealias.aliases[self.attributes['key']] = self.attributes['text'] 854 return res 855 856class citetalias(citet): 857 args = 'bibkeys:list:str' 858 def citation(self): 859 return citet.citation(self, text=defcitealias.aliases.get(self.attributes['bibkeys'][0],'')) 860 861class citepalias(citep): 862 args = 'bibkeys:list:str' 863 def citation(self): 864 return citep.citation(self, text=defcitealias.aliases.get(self.attributes['bibkeys'][0],'')) 865 866class shortcites(Base.Command): 867 args = 'bibkeys:list:str' 868 869class urlstyle(Base.Command): 870 pass 871