1# -*- coding: utf-8 -*- 2#!/usr/bin/env python 3# 4# Gramps - a GTK+/GNOME based genealogy program 5# 6# Copyright (C) 2000-2007 Donald N. Allingham 7# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com> 8# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk> 9# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com> 10# Copyright (C) 2008-2009 Brian G. Matherly 11# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com> 12# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com> 13# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com> 14# Copyright (C) 2010 Jakim Friant 15# Copyright (C) 2010- Serge Noiraud 16# Copyright (C) 2011 Tim G L Lyons 17# Copyright (C) 2013 Benny Malengier 18# Copyright (C) 2016 Allen Crider 19# Copyright (C) 2018 Theo van Rijn 20# 21# This program is free software; you can redistribute it and/or modify 22# it under the terms of the GNU General Public License as published by 23# the Free Software Foundation; either version 2 of the License, or 24# (at your option) any later version. 25# 26# This program is distributed in the hope that it will be useful, 27# but WITHOUT ANY WARRANTY; without even the implied warranty of 28# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29# GNU General Public License for more details. 30# 31# You should have received a copy of the GNU General Public License 32# along with this program; if not, write to the Free Software 33# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 34# 35 36""" 37Narrative Web Page generator. 38 39Classe: 40 BasePage - super class for producing a web page. This class is instantiated 41 once for each page. Provdes various common functions. 42""" 43#------------------------------------------------ 44# python modules 45#------------------------------------------------ 46from functools import partial 47import os 48import copy 49import datetime 50from decimal import getcontext 51 52#------------------------------------------------ 53# Set up logging 54#------------------------------------------------ 55import logging 56 57#------------------------------------------------ 58# Gramps module 59#------------------------------------------------ 60from gramps.gen.const import GRAMPS_LOCALE as glocale 61from gramps.gen.lib import (FamilyRelType, NoteType, NameType, Person, 62 UrlType, Name, PlaceType, EventRoleType, 63 Family, Citation, Place, Date) 64from gramps.gen.lib.date import Today 65from gramps.gen.const import PROGRAM_NAME, URL_HOMEPAGE 66from gramps.version import VERSION 67from gramps.gen.plug.report import Bibliography 68from gramps.gen.plug.report import utils 69from gramps.gen.utils.config import get_researcher 70from gramps.gen.utils.string import conf_strings 71from gramps.gen.utils.file import media_path_full 72from gramps.gen.utils.thumbnails import get_thumbnail_path 73from gramps.gen.display.name import displayer as _nd 74from gramps.gen.display.place import displayer as _pd 75from gramps.plugins.lib.libhtmlconst import _CC 76from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback 77from gramps.gen.datehandler import parser as _dp 78from gramps.plugins.lib.libhtml import Html, xml_lang 79from gramps.plugins.lib.libhtmlbackend import HtmlBackend, process_spaces 80from gramps.gen.utils.place import conv_lat_lon 81from gramps.gen.utils.location import get_main_location 82from gramps.plugins.webreport.common import (_NAME_STYLE_DEFAULT, HTTP, 83 _NAME_STYLE_FIRST, HTTPS, 84 _get_short_name, 85 add_birthdate, CSS, html_escape, 86 _NARRATIVESCREEN, _NARRATIVEPRINT, 87 FULLCLEAR, _has_webpage_extension) 88 89_ = glocale.translation.sgettext 90LOG = logging.getLogger(".NarrativeWeb") 91getcontext().prec = 8 92 93class BasePage: # pylint: disable=C1001 94 """ 95 Manages all the functions, variables, and everything needed 96 for all of the classes contained within this plugin 97 """ 98 def __init__(self, report, title, gid=None): 99 """ 100 @param: report -- The instance of the main report class for 101 this report 102 @param: title -- Is the title of the web page 103 @param: gid -- The family gramps ID 104 """ 105 self.uplink = False 106 # class to do conversion of styled notes to html markup 107 self._backend = HtmlBackend() 108 self._backend.build_link = report.build_link 109 110 self.report = report 111 self.r_db = report.database 112 self.r_user = report.user 113 self.title_str = title 114 self.gid = gid 115 self.bibli = Bibliography() 116 117 self.page_title = "" 118 119 self.author = get_researcher().get_name() 120 if self.author: 121 self.author = self.author.replace(',,,', '') 122 123 # TODO. All of these attributes are not necessary, because we have 124 # also the options in self.options. Besides, we need to check which 125 # are still required. 126 self.html_dir = report.options['target'] 127 self.ext = report.options['ext'] 128 self.noid = not report.options['inc_id'] 129 self.linkhome = report.options['linkhome'] 130 self.create_media = report.options['gallery'] 131 self.create_unused_media = report.options['unused'] 132 self.create_thumbs_only = report.options['create_thumbs_only'] 133 self.inc_families = report.options['inc_families'] 134 self.inc_events = report.options['inc_events'] 135 self.usecms = report.options['usecms'] 136 self.prevnext = report.options['prevnext'] 137 self.target_uri = report.options['cmsuri'] 138 self.usecal = report.options['usecal'] 139 self.target_cal_uri = report.options['caluri'] 140 self.extrapage = report.options['extrapage'] 141 self.extrapagename = report.options['extrapagename'] 142 self.familymappages = None 143 self.reference_sort = report.options['reference_sort'] 144 lang = report.options['trans'] 145 self.rlocale = report.set_locale(lang) 146 self._ = self.rlocale.translation.sgettext 147 self.colon = self._(':') # translators: needed for French, else ignore 148 149 if report.options['securesite']: 150 self.secure_mode = HTTPS 151 else: 152 self.secure_mode = HTTP 153 154 # Functions used when no Web Page plugin is provided 155 def add_instance(self, *param): 156 """ 157 Add an instance 158 """ 159 pass 160 161 def display_pages(self, title): 162 """ 163 Display the pages 164 """ 165 pass 166 167 def sort_on_name_and_grampsid(self, handle): 168 """ Used to sort on name and gramps ID. """ 169 person = self.r_db.get_person_from_handle(handle) 170 name = _nd.display(person) 171 return (name, person.get_gramps_id()) 172 173 def sort_on_given_and_birth(self, handle): 174 """ Used to sort on given name and birth date. """ 175 person = self.r_db.get_person_from_handle(handle) 176 name = _nd.display_given(person) 177 bd_event = get_birth_or_fallback(self.r_db, person) 178 birth = "" 179 if bd_event: 180 birth_iso = str(bd_event.get_date_object()).replace('abt ', '') 181 # we need to remove abt, bef, aft, ... 182 birth = birth_iso.replace('aft ', '').replace('bef ', '') 183 return (name, birth) 184 185 def sort_on_grampsid(self, event_ref): 186 """ 187 Sort on gramps ID 188 """ 189 evt = self.r_db.get_event_from_handle( 190 event_ref.ref) 191 return evt.get_gramps_id() 192 193 def copy_thumbnail(self, handle, photo, region=None): 194 """ 195 Given a handle (and optional region) make (if needed) an 196 up-to-date cache of a thumbnail, and call report.copy_file 197 to copy the cached thumbnail to the website. 198 Return the new path to the image. 199 """ 200 to_dir = self.report.build_path('thumb', handle) 201 to_path = os.path.join(to_dir, handle) + ( 202 ('%d,%d-%d,%d.png' % region) if region else '.png' 203 ) 204 205 if photo.get_mime_type(): 206 full_path = media_path_full(self.r_db, photo.get_path()) 207 from_path = get_thumbnail_path(full_path, 208 photo.get_mime_type(), 209 region) 210 if not os.path.isfile(from_path): 211 from_path = CSS["Document"]["filename"] 212 else: 213 from_path = CSS["Document"]["filename"] 214 self.report.copy_file(from_path, to_path) 215 return to_path 216 217 def get_nav_menu_hyperlink(self, url_fname, nav_text): 218 """ 219 Returns the navigation menu hyperlink 220 """ 221 if url_fname == self.target_cal_uri: 222 uplink = False 223 else: 224 uplink = self.uplink 225 226 # check for web page file extension? 227 if not _has_webpage_extension(url_fname): 228 url_fname += self.ext 229 230 # get menu item url and begin hyperlink... 231 url = self.report.build_url_fname(url_fname, None, uplink) 232 233 return Html("a", nav_text, href=url, title=nav_text, inline=True) 234 235 def get_column_data(self, unordered, data_list, column_title): 236 """ 237 Returns the menu column for Drop Down Menus and Drop Down Citations 238 """ 239 if not data_list: 240 return 241 242 elif len(data_list) == 1: 243 url_fname, nav_text = data_list[0][0], data_list[0][1] 244 hyper = self.get_nav_menu_hyperlink(url_fname, nav_text) 245 unordered.extend( 246 Html("li", hyper, inline=True) 247 ) 248 else: 249 col_list = Html("li") + ( 250 Html("a", column_title, href="#", 251 title=column_title, inline=True) 252 ) 253 unordered += col_list 254 255 unordered1 = Html("ul") 256 col_list += unordered1 257 258 for url_fname, nav_text in data_list: 259 hyper = self.get_nav_menu_hyperlink(url_fname, nav_text) 260 unordered1.extend(Html("li", hyper, inline=True)) 261 262 def display_relationships(self, individual, place_lat_long): 263 """ 264 Displays a person's relationships ... 265 266 @param: family_handle_list -- families in this report database 267 @param: place_lat_long -- for use in Family Map Pages. 268 This will be None if called from 269 Family pages, which do not create 270 a Family Map 271 """ 272 family_list = individual.get_family_handle_list() 273 if not family_list: 274 return None 275 276 with Html("div", class_="subsection", id="families") as section: 277 section += Html("h4", self._("Families"), inline=True) 278 279 table_class = "infolist" 280 if len(family_list) > 1: 281 table_class += " fixed_subtables" 282 with Html("table", class_=table_class) as table: 283 section += table 284 285 for family_handle in family_list: 286 family = self.r_db.get_family_from_handle(family_handle) 287 if family: 288 link = self.family_link( 289 family_handle, 290 self.report.obj_dict[Family][family_handle][1], 291 gid=family.get_gramps_id(), uplink=True) 292 link1 = Html("H4", link, class_="subsection") 293 trow = Html("tr", class_="BeginFamily") + ( 294 Html("td", link1, class_="ColumnValue", colspan=3, 295 inline=True) 296 ) 297 table += trow 298 # find the spouse of the principal individual and 299 # display that person 300 sp_hdl = utils.find_spouse(individual, family) 301 if sp_hdl: 302 spouse = self.r_db.get_person_from_handle(sp_hdl) 303 if spouse: 304 table += self.display_spouse(spouse, family, 305 place_lat_long) 306 307 details = self.display_family_details(family, 308 place_lat_long) 309 if details is not None: 310 table += details 311 return section 312 313 def display_family_relationships(self, family, place_lat_long): 314 """ 315 Displays a family's relationships ... 316 317 @param: family -- the family to be displayed 318 @param: place_lat_long -- for use in Family Map Pages. This will 319 be None if called from Family pages, which 320 do not create a Family Map 321 """ 322 with Html("div", class_="subsection", id="families") as section: 323 section += Html("h4", self._("Families"), inline=True) 324 325 table_class = "infolist" 326 with Html("table", class_=table_class) as table: 327 section += table 328 for person_hdl in [family.get_father_handle(), 329 family.get_mother_handle()]: 330 person = None 331 if person_hdl: 332 person = self.r_db.get_person_from_handle(person_hdl) 333 if person: 334 table += self.display_spouse(person, 335 family, place_lat_long) 336 337 details = self.display_family_details(family, place_lat_long) 338 if details is not None: 339 table += details 340 return section 341 342 def display_family_details(self, family, place_lat_long): 343 """ 344 Display details about one family: family events, children, family LDS 345 ordinances, family attributes 346 """ 347 table = None 348 birthorder = self.report.options["birthorder"] 349 # display family events; such as marriage and divorce... 350 family_events = family.get_event_ref_list() 351 if family_events: 352 trow = Html("tr") + ( 353 Html("td", " ", class_="ColumnType", inline=True), 354 Html("td", " ", class_="ColumnAttribute", inline=True), 355 Html("td", self.format_family_events(family_events, 356 place_lat_long), 357 class_="ColumnValue") 358 ) 359 table = trow 360 361 # If the families pages are not output, display family notes 362 if not self.inc_families: 363 notelist = family.get_note_list() 364 for notehandle in notelist: 365 note = self.r_db.get_note_from_handle(notehandle) 366 if note: 367 trow = Html("tr") + ( 368 Html("td", " ", class_="ColumnType", inline=True), 369 Html("td", self._("Narrative"), 370 class_="ColumnAttribute", 371 inline=True), 372 Html("td", self.get_note_format(note, True), 373 class_="ColumnValue") 374 ) 375 table = table + trow if table is not None else trow 376 377 childlist = family.get_child_ref_list() 378 if childlist: 379 trow = Html("tr") + ( 380 Html("td", " ", class_="ColumnType", inline=True), 381 Html("td", self._("Children"), class_="ColumnAttribute", 382 inline=True) 383 ) 384 table = table + trow if table is not None else trow 385 386 tcell = Html("td", class_="ColumnValue", close=False) 387 trow += tcell 388 389 with Html("table", class_="infolist eventlist") as table2: 390 thead = Html("thead") 391 table2 += thead 392 header = Html("tr") 393 394 header.extend( 395 Html("th", label, class_=colclass, inline=True) 396 for (label, colclass) in [ 397 [self._("Name"), "ColumnName"], 398 [self._("Birth Date"), "ColumnDate"], 399 [self._("Death Date"), "ColumnDate"], 400 ] 401 ) 402 thead += header 403 404 # begin table body 405 tbody = Html("tbody") 406 table2 += tbody 407 408 childlist = [child_ref.ref for child_ref in childlist] 409 410 # add individual's children event places to family map... 411 if self.familymappages: 412 for handle in childlist: 413 child = self.r_db.get_person_from_handle(handle) 414 if child: 415 self._get_event_place(child, place_lat_long) 416 417 children = add_birthdate(self.r_db, childlist, self.rlocale) 418 if birthorder: 419 children = sorted(children) 420 421 tbody.extend((Html("tr", inline=True) + 422 Html("td", inline=True, close=False) + 423 self.display_child_link(chandle) + 424 Html("td", birth, inline=True) + 425 Html("td", death, inline=True)) 426 for birth_date, birth, death, chandle in children 427 ) 428 trow += table2 429 430 # family LDS ordinance list 431 family_lds_ordinance_list = family.get_lds_ord_list() 432 if family_lds_ordinance_list: 433 trow = Html("tr") + ( 434 Html("td", " ", class_="ColumnType", inline=True), 435 Html("td", self._("LDS Ordinance"), class_="ColumnAttribute", 436 inline=True), 437 Html("td", self.dump_ordinance(family, "Family"), 438 class_="ColumnValue") 439 ) 440 table = table + trow if table is not None else trow 441 442 # Family Attribute list 443 family_attribute_list = family.get_attribute_list() 444 if family_attribute_list: 445 trow = Html("tr") + ( 446 Html("td", " ", class_="ColumnType", inline=True), 447 Html("td", self._("Attributes"), class_="ColumnAttribute", 448 inline=True) 449 ) 450 table = table + trow if table is not None else trow 451 452 tcell = Html("td", class_="ColumnValue") 453 trow += tcell 454 455 # we do not need the section variable for this instance 456 # of Attributes... 457 dummy, attrtable = self.display_attribute_header() 458 tcell += attrtable 459 self.display_attr_list(family_attribute_list, attrtable) 460 return table 461 462 def complete_people(self, tcell, first_person, handle_list, uplink=True): 463 """ 464 completes the person column for classes EventListPage and EventPage 465 466 @param: tcell -- table cell from its caller 467 @param: first_person -- Not used any more, done via css 468 @param: handle_list -- handle list from the backlink of 469 the event_handle 470 """ 471 dummy_first_person = first_person 472 for (classname, handle) in handle_list: 473 474 # personal event 475 if classname == "Person": 476 tcell += Html("span", self.new_person_link(handle, uplink), 477 class_="person", inline=True) 478 479 # family event 480 else: 481 _obj = self.r_db.get_family_from_handle(handle) 482 if _obj: 483 484 # husband and spouse in this example, 485 # are called father and mother 486 husband_handle = _obj.get_father_handle() 487 if husband_handle: 488 hlink = self.new_person_link(husband_handle, uplink) 489 spouse_handle = _obj.get_mother_handle() 490 if spouse_handle: 491 slink = self.new_person_link(spouse_handle, uplink) 492 493 if spouse_handle and husband_handle: 494 tcell += Html("span", hlink, class_="father", 495 inline=True) 496 tcell += Html("span", slink, class_="mother", 497 inline=True) 498 elif spouse_handle: 499 tcell += Html("span", slink, class_="mother", 500 inline=True) 501 elif husband_handle: 502 tcell += Html("span", hlink, class_="father", 503 inline=True) 504 return tcell 505 506 def dump_attribute(self, attr): 507 """ 508 dump attribute for object presented in display_attr_list() 509 510 @param: attr = attribute object 511 """ 512 trow = Html("tr") 513 514 trow.extend( 515 Html("td", data or " ", class_=colclass, 516 inline=True if (colclass == "Type" or "Sources") else False) 517 for (data, colclass) in [ 518 (str(attr.get_type()), "ColumnType"), 519 (attr.get_value(), "ColumnValue"), 520 (self.dump_notes(attr.get_note_list()), "ColumnNotes"), 521 (self.get_citation_links(attr.get_citation_list()), 522 "ColumnSources") 523 ] 524 ) 525 return trow 526 527 def get_citation_links(self, citation_handle_list): 528 """ 529 get citation link from the citation handle list 530 531 @param: citation_handle_list = list of gen/lib/Citation 532 """ 533 text = "" 534 for citation_handle in citation_handle_list: 535 citation = self.r_db.get_citation_from_handle(citation_handle) 536 if citation: 537 index, key = self.bibli.add_reference(citation) 538 id_ = "%d%s" % (index+1, key) 539 text += ' <a href="#sref%s">%s</a>' % (id_, id_) 540 return text 541 542 def get_note_format(self, note, link_prefix_up): 543 """ 544 will get the note from the database, and will return either the 545 styled text or plain note 546 """ 547 self.report.link_prefix_up = link_prefix_up 548 549 text = "" 550 if note is not None: 551 # retrieve the body of the note 552 note_text = note.get() 553 554 # styled notes 555 htmlnotetext = self.styled_note( 556 note.get_styledtext(), note.get_format(), 557 contains_html=(note.get_type() == NoteType.HTML_CODE)) 558 text = htmlnotetext or Html("p", note_text) 559 560 # return text of the note to its callers 561 return text 562 563 def styled_note(self, styledtext, styled_format, contains_html=False): 564 """ 565 styledtext : assumed a StyledText object to write 566 styled_format : = 0 : Flowed, = 1 : Preformatted 567 style_name : name of the style to use for default presentation 568 """ 569 text = str(styledtext) 570 571 if not text: 572 return '' 573 574 s_tags = styledtext.get_tags() 575 htmllist = Html("div", class_="grampsstylednote") 576 if contains_html: 577 markuptext = self._backend.add_markup_from_styled(text, 578 s_tags, 579 split='\n', 580 escape=False) 581 htmllist += markuptext 582 else: 583 markuptext = self._backend.add_markup_from_styled(text, 584 s_tags, 585 split='\n') 586 linelist = [] 587 linenb = 1 588 for line in markuptext.split('\n'): 589 [line, sigcount] = process_spaces(line, styled_format) 590 if sigcount == 0: 591 # The rendering of an empty paragraph '<p></p>' 592 # is undefined so we use a non-breaking space 593 if linenb == 1: 594 linelist.append(' ') 595 htmllist.extend(Html('p') + linelist) 596 linelist = [] 597 linenb = 1 598 else: 599 if linenb > 1: 600 linelist[-1] += '<br />' 601 linelist.append(line) 602 linenb += 1 603 if linenb > 1: 604 htmllist.extend(Html('p') + linelist) 605 # if the last line was blank, then as well as outputting 606 # the previous para, which we have just done, 607 # we also output a new blank para 608 if sigcount == 0: 609 linelist = [" "] 610 htmllist.extend(Html('p') + linelist) 611 return htmllist 612 613 def dump_notes(self, notelist): 614 """ 615 dump out of list of notes with very little elements of its own 616 617 @param: notelist -- list of notes 618 """ 619 if not notelist: 620 return Html("div") 621 622 # begin unordered list 623 notesection = Html("div") 624 for notehandle in notelist: 625 this_note = self.r_db.get_note_from_handle(notehandle) 626 if this_note is not None: 627 notesection.extend(Html("i", self._(this_note.type.xml_str()), 628 class_="NoteType")) 629 notesection.extend(self.get_note_format(this_note, True)) 630 return notesection 631 632 def event_header_row(self): 633 """ 634 creates the event header row for all events 635 """ 636 trow = Html("tr", close=None) 637 trow.extend( 638 Html("th", trans, class_=colclass, inline=True) 639 for trans, colclass in [ 640 (self._("Event"), "ColumnEvent"), 641 (self._("Date"), "ColumnDate"), 642 (self._("Place"), "ColumnPlace"), 643 (self._("Description"), "ColumnDescription"), 644 (self._("Sources"), "ColumnSources")] 645 ) 646 trow += Html("/tr", close=None) 647 return trow 648 649 def display_event_row(self, event, event_ref, place_lat_long, 650 uplink, hyperlink, omit): 651 """ 652 display the event row for IndividualPage 653 654 @param: evt -- Event object from report database 655 @param: evt_ref -- Event reference 656 @param: place_lat_long -- For use in Family Map Pages. This will be 657 None if called from Family pages, which do 658 not create a Family Map 659 @param: uplink -- If True, then "../../../" is inserted in 660 front of the result. 661 @param: hyperlink -- Add a hyperlink or not 662 @param: omit -- Role to be omitted in output 663 """ 664 event_gid = event.get_gramps_id() 665 666 place_handle = event.get_place_handle() 667 if place_handle: 668 place = self.r_db.get_place_from_handle(place_handle) 669 if place: 670 self.append_to_place_lat_long(place, event, place_lat_long) 671 672 # begin event table row 673 trow = Html("tr") 674 675 # get event type and hyperlink to it or not? 676 etype = self._(event.get_type().xml_str()) 677 678 event_role = event_ref.get_role() 679 if not event_role == omit: 680 etype += " (%s)" % event_role 681 event_hyper = self.event_link(event_ref.ref, 682 etype, 683 event_gid, 684 uplink) if hyperlink else etype 685 trow += Html("td", event_hyper, class_="ColumnEvent") 686 687 # get event data 688 event_data = self.get_event_data(event, event_ref, uplink) 689 690 trow.extend( 691 Html("td", data or " ", class_=colclass, 692 inline=(not data or colclass == "ColumnDate")) 693 for (label, colclass, data) in event_data 694 ) 695 696 trow2 = Html("tr") 697 trow2 += Html("td", "", class_="ColumnEvent") 698 # get event source references 699 srcrefs = self.get_citation_links(event.get_citation_list()) or " " 700 trow += Html("td", srcrefs, class_="ColumnSources", rowspan=2) 701 702 # get event notes 703 notelist = event.get_note_list()[:] # we don't want to modify 704 # cached original 705 notelist.extend(event_ref.get_note_list()) 706 htmllist = self.dump_notes(notelist) 707 708 # if the event or event reference has an attribute attached to it, 709 # get the text and format it correctly? 710 attrlist = event.get_attribute_list()[:] # we don't want to modify 711 # cached original 712 attrlist.extend(event_ref.get_attribute_list()) 713 for attr in attrlist: 714 htmllist.extend(Html("p", 715 _("%(str1)s: %(str2)s") % { 716 'str1' : Html("b", attr.get_type()), 717 'str2' : attr.get_value() 718 })) 719 720 #also output notes attached to the attributes 721 notelist = attr.get_note_list() 722 if notelist: 723 htmllist.extend(self.dump_notes(notelist)) 724 725 trow2 += Html("td", htmllist, class_="ColumnNotes", colspan=3) 726 727 trow += trow2 728 # return events table row to its callers 729 return trow 730 731 def append_to_place_lat_long(self, place, event, place_lat_long): 732 """ 733 Create a list of places with coordinates. 734 735 @param: place_lat_long -- for use in Family Map Pages. This will be 736 None if called from Family pages, which do 737 not create a Family Map 738 """ 739 if place_lat_long is None: 740 return 741 place_handle = place.get_handle() 742 event_date = event.get_date_object() 743 744 # 0 = latitude, 1 = longitude, 2 - placetitle, 745 # 3 = place handle, 4 = event date, 5 = event type 746 found = any(data[3] == place_handle and data[4] == event_date 747 for data in place_lat_long) 748 if not found: 749 placetitle = _pd.display(self.r_db, place) 750 latitude = place.get_latitude() 751 longitude = place.get_longitude() 752 if latitude and longitude: 753 latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") 754 if latitude is not None: 755 etype = event.get_type() 756 place_lat_long.append([latitude, longitude, placetitle, 757 place_handle, event_date, etype]) 758 759 def _get_event_place(self, person, place_lat_long): 760 """ 761 Retrieve from a person their events, and places for family map 762 763 @param: person -- Person object from the database 764 @param: place_lat_long -- For use in Family Map Pages. This will be 765 None if called from Family pages, which do 766 not create a Family Map 767 """ 768 if not person: 769 return 770 771 # check to see if this person is in the report database? 772 use_link = self.report.person_in_webreport(person.get_handle()) 773 if use_link: 774 evt_ref_list = person.get_event_ref_list() 775 if evt_ref_list: 776 for evt_ref in evt_ref_list: 777 event = self.r_db.get_event_from_handle(evt_ref.ref) 778 if event: 779 pl_handle = event.get_place_handle() 780 if pl_handle: 781 place = self.r_db.get_place_from_handle(pl_handle) 782 if place: 783 self.append_to_place_lat_long(place, event, 784 place_lat_long) 785 786 def family_link(self, family_handle, name, gid=None, uplink=False): 787 """ 788 Create the url and link for FamilyPage 789 790 @param: family_handle -- The handle for the family to link 791 @param: name -- The family name 792 @param: gid -- The family gramps ID 793 @param: uplink -- If True, then "../../../" is inserted in 794 front of the result. 795 """ 796 name = html_escape(name) 797 if not self.noid and gid: 798 gid_html = Html("span", " [%s]" % gid, class_="grampsid", 799 inline=True) 800 else: 801 gid_html = "" 802 803 result = self.report.obj_dict.get(Family).get(family_handle) 804 if result is None: 805 # the family is not included in the webreport 806 return name + str(gid_html) 807 808 url = self.report.build_url_fname(result[0], uplink=uplink) 809 hyper = Html("a", name, href=url, title=name) 810 hyper += gid_html 811 return hyper 812 813 def get_family_string(self, family): 814 """ 815 Unused method ??? 816 Returns a hyperlink for each person linked to the Family Page 817 818 @param: family -- The family 819 """ 820 husband, spouse = [False]*2 821 822 husband_handle = family.get_father_handle() 823 824 if husband_handle: 825 husband = self.r_db.get_person_from_handle(husband_handle) 826 else: 827 husband = None 828 829 spouse_handle = family.get_mother_handle() 830 if spouse_handle: 831 spouse = self.r_db.get_person_from_handle(spouse_handle) 832 else: 833 spouse = None 834 835 if husband: 836 husband_name = self.get_name(husband) 837 hlink = self.family_link(family.get_handle(), 838 husband_name, uplink=self.uplink) 839 if spouse: 840 spouse_name = self.get_name(spouse) 841 slink = self.family_link(family.get_handle(), 842 spouse_name, uplink=self.uplink) 843 844 title_str = '' 845 if husband and spouse: 846 title_str = '%s ' % hlink + self._("and") + ' %s' % slink 847 elif husband: 848 title_str = '%s ' % hlink 849 elif spouse: 850 title_str = '%s ' % slink 851 return title_str 852 853 def event_link(self, event_handle, event_title, gid=None, uplink=False): 854 """ 855 Creates a hyperlink for an event based on its type 856 857 @param: event_handle -- Event handle 858 @param: event_title -- Event title 859 @param: gid -- The gramps ID for the event 860 @param: uplink -- If True, then "../../../" is inserted in front 861 of the result. 862 """ 863 if not self.inc_events: 864 return event_title 865 866 url = self.report.build_url_fname_html(event_handle, "evt", uplink) 867 hyper = Html("a", event_title, href=url, title=event_title) 868 869 if not self.noid and gid: 870 hyper += Html("span", " [%s]" % gid, class_="grampsid", inline=True) 871 return hyper 872 873 def format_family_events(self, event_ref_list, place_lat_long): 874 """ 875 displays the event row for events such as marriage and divorce 876 877 @param: event_ref_list -- List of events reference 878 @param: place_lat_long -- For use in Family Map Pages. This will be 879 None if called from Family pages, which do 880 not create a Family Map 881 """ 882 with Html("table", class_="infolist eventlist") as table: 883 thead = Html("thead") 884 table += thead 885 886 # attach event header row 887 thead += self.event_header_row() 888 889 # begin table body 890 tbody = Html("tbody") 891 table += tbody 892 893 for evt_ref in event_ref_list: 894 event = self.r_db.get_event_from_handle(evt_ref.ref) 895 896 # add event body row 897 tbody += self.display_event_row(event, evt_ref, place_lat_long, 898 uplink=True, hyperlink=True, 899 omit=EventRoleType.FAMILY) 900 return table 901 902 def get_event_data(self, evt, evt_ref, 903 uplink, gid=None): 904 """ 905 retrieve event data from event and evt_ref 906 907 @param: evt -- Event from database 908 @param: evt_ref -- Event reference 909 @param: uplink -- If True, then "../../../" is inserted in front of 910 the result. 911 """ 912 dummy_evt_ref = evt_ref 913 dummy_gid = gid 914 place = None 915 place_handle = evt.get_place_handle() 916 if place_handle: 917 place = self.r_db.get_place_from_handle(place_handle) 918 919 place_hyper = None 920 if place: 921 place_name = _pd.display(self.r_db, place, evt.get_date_object()) 922 place_hyper = self.place_link(place_handle, place_name, 923 uplink=uplink) 924 925 evt_desc = evt.get_description() 926 927 # wrap it all up and return to its callers 928 # position 0 = translatable label, position 1 = column class 929 # position 2 = data 930 return [(self._("Date"), "ColumnDate", 931 self.rlocale.get_date(evt.get_date_object())), 932 (self._("Place"), "ColumnPlace", place_hyper), 933 (self._("Description"), "ColumnDescription", evt_desc)] 934 935 def dump_ordinance(self, ldsobj, ldssealedtype): 936 """ 937 will dump the LDS Ordinance information for either 938 a person or a family ... 939 940 @param: ldsobj -- Either person or family 941 @param: ldssealedtype -- Either Sealed to Family or Spouse 942 """ 943 dummy_ldssealedtype = ldssealedtype 944 objectldsord = ldsobj.get_lds_ord_list() 945 if not objectldsord: 946 return None 947 948 # begin LDS ordinance table and table head 949 with Html("table", class_="infolist ldsordlist") as table: 950 thead = Html("thead") 951 table += thead 952 953 # begin HTML row 954 trow = Html("tr") 955 thead += trow 956 957 trow.extend( 958 Html("th", label, class_=colclass, inline=True) 959 for (label, colclass) in [ 960 [self._("Type"), "ColumnLDSType"], 961 [self._("Date"), "ColumnDate"], 962 [self._("Temple"), "ColumnLDSTemple"], 963 [self._("Place"), "ColumnLDSPlace"], 964 [self._("Status"), "ColumnLDSStatus"], 965 [self._("Sources"), "ColumnLDSSources"] 966 ] 967 ) 968 969 # start table body 970 tbody = Html("tbody") 971 table += tbody 972 973 for ordobj in objectldsord: 974 place_hyper = " " 975 place_handle = ordobj.get_place_handle() 976 if place_handle: 977 place = self.r_db.get_place_from_handle(place_handle) 978 if place: 979 place_title = _pd.display(self.r_db, place) 980 place_hyper = self.place_link( 981 place_handle, place_title, 982 place.get_gramps_id(), uplink=True) 983 984 # begin ordinance rows 985 trow = Html("tr") 986 987 trow.extend( 988 Html("td", value or " ", class_=colclass, 989 inline=(not value or colclass == "ColumnDate")) 990 for (value, colclass) in [ 991 (ordobj.type2xml(), "ColumnType"), 992 (self.rlocale.get_date(ordobj.get_date_object()), 993 "ColumnDate"), 994 (ordobj.get_temple(), "ColumnLDSTemple"), 995 (place_hyper, "ColumnLDSPlace"), 996 (ordobj.get_status(), "ColumnLDSStatus"), 997 (self.get_citation_links(ordobj.get_citation_list()), 998 "ColumnSources") 999 ] 1000 ) 1001 tbody += trow 1002 return table 1003 1004 def write_srcattr(self, srcattr_list): 1005 """ 1006 Writes out the srcattr for the different objects 1007 1008 @param: srcattr_list -- List of source attributes 1009 """ 1010 if not srcattr_list: 1011 return None 1012 1013 # begin data map division and section title... 1014 with Html("div", class_="subsection", id="data_map") as section: 1015 section += Html("h4", self._("Attributes"), inline=True) 1016 1017 with Html("table", class_="infolist") as table: 1018 section += table 1019 1020 thead = Html("thead") 1021 table += thead 1022 1023 trow = Html("tr") + ( 1024 Html("th", self._("Key"), class_="ColumnAttribute", 1025 inline=True), 1026 Html("th", self._("Value"), class_="ColumnValue", 1027 inline=True) 1028 ) 1029 thead += trow 1030 1031 tbody = Html("tbody") 1032 table += tbody 1033 1034 for srcattr in srcattr_list: 1035 trow = Html("tr") + ( 1036 Html("td", str(srcattr.get_type()), 1037 class_="ColumnAttribute", inline=True), 1038 Html("td", srcattr.get_value(), 1039 class_="ColumnValue", inline=True) 1040 ) 1041 tbody += trow 1042 return section 1043 1044 def source_link(self, source_handle, source_title, 1045 gid=None, cindex=None, uplink=False): 1046 """ 1047 Creates a link to the source object 1048 1049 @param: source_handle -- Source handle from database 1050 @param: source_title -- Title from the source object 1051 @param: gid -- Source gramps id from the source object 1052 @param: cindex -- Count index 1053 @param: uplink -- If True, then "../../../" is inserted in 1054 front of the result. 1055 """ 1056 url = self.report.build_url_fname_html(source_handle, "src", uplink) 1057 hyper = Html("a", source_title, 1058 href=url, 1059 title=source_title) 1060 1061 # if not None, add name reference to hyperlink element 1062 if cindex: 1063 hyper.attr += ' name ="sref%d"' % cindex 1064 1065 # add Gramps ID 1066 if not self.noid and gid: 1067 hyper += Html("span", ' [%s]' % gid, class_="grampsid", inline=True) 1068 return hyper 1069 1070 def display_addr_list(self, addrlist, showsrc): 1071 """ 1072 Display a person's or repository's addresses ... 1073 1074 @param: addrlist -- a list of address handles 1075 @param: showsrc -- True = show sources 1076 False = do not show sources 1077 None = djpe 1078 """ 1079 if not addrlist: 1080 return None 1081 1082 # begin addresses division and title 1083 with Html("div", class_="subsection", id="Addresses") as section: 1084 section += Html("h4", self._("Addresses"), inline=True) 1085 1086 # write out addresses() 1087 section += self.dump_addresses(addrlist, showsrc) 1088 1089 # return address division to its caller 1090 return section 1091 1092 def dump_addresses(self, addrlist, showsrc): 1093 """ 1094 will display an object's addresses, url list, note list, 1095 and source references. 1096 1097 @param: addrlist = either person or repository address list 1098 @param: showsrc = True -- person and their sources 1099 False -- repository with no sources 1100 None -- Address Book address with sources 1101 """ 1102 if not addrlist: 1103 return None 1104 1105 # begin summaryarea division 1106 with Html("div", id="AddressTable") as summaryarea: 1107 1108 # begin address table 1109 with Html("table") as table: 1110 summaryarea += table 1111 1112 # get table class based on showsrc 1113 if showsrc is True: 1114 table.attr = 'class = "infolist addrlist"' 1115 elif showsrc is False: 1116 table.attr = 'class = "infolist repolist"' 1117 else: 1118 table.attr = 'class = "infolist addressbook"' 1119 1120 # begin table head 1121 thead = Html("thead") 1122 table += thead 1123 1124 trow = Html("tr") 1125 thead += trow 1126 1127 addr_header = [[self._("Date"), "Date"], 1128 [self._("Street"), "StreetAddress"], 1129 [self._("Locality"), "Locality"], 1130 [self._("City"), "City"], 1131 [self._("State/ Province"), "State"], 1132 [self._("County"), "County"], 1133 [self._("Postal Code"), "Postalcode"], 1134 [self._("Country"), "Cntry"], 1135 [self._("Phone"), "Phone"]] 1136 1137 # True, False, or None ** see docstring for explanation 1138 if showsrc in [True, None]: 1139 addr_header.append([self._("Sources"), "Sources"]) 1140 1141 trow.extend( 1142 Html("th", self._(label), 1143 class_="Colummn" + colclass, inline=True) 1144 for (label, colclass) in addr_header 1145 ) 1146 1147 # begin table body 1148 tbody = Html("tbody") 1149 table += tbody 1150 1151 # get address list from an object; either repository or person 1152 for address in addrlist: 1153 1154 trow = Html("tr") 1155 tbody += trow 1156 1157 addr_data_row = [ 1158 (self.rlocale.get_date(address.get_date_object()), 1159 "ColumnDate"), 1160 (address.get_street(), "ColumnStreetAddress"), 1161 (address.get_locality(), "ColumnLocality"), 1162 (address.get_city(), "ColumnCity"), 1163 (address.get_state(), "ColumnState"), 1164 (address.get_county(), "ColumnCounty"), 1165 (address.get_postal_code(), "ColumnPostalCode"), 1166 (address.get_country(), "ColumnCntry"), 1167 (address.get_phone(), "ColumnPhone") 1168 ] 1169 1170 # get source citation list 1171 if showsrc in [True, None]: 1172 addr_data_row.append( 1173 [self.get_citation_links( 1174 address.get_citation_list()), 1175 "ColumnSources"]) 1176 1177 trow.extend( 1178 Html("td", value or " ", 1179 class_=colclass, inline=True) 1180 for (value, colclass) in addr_data_row 1181 ) 1182 1183 # address: notelist 1184 if showsrc is not None: 1185 notelist = self.display_note_list( 1186 address.get_note_list()) 1187 if notelist is not None: 1188 summaryarea += notelist 1189 return summaryarea 1190 1191 def addressbook_link(self, person_handle, uplink=False): 1192 """ 1193 Creates a hyperlink for an address book link based on person's handle 1194 1195 @param: person_handle -- Person's handle from the database 1196 @param: uplink -- If True, then "../../../" is inserted in 1197 front of the result. 1198 """ 1199 url = self.report.build_url_fname_html(person_handle, "addr", uplink) 1200 person = self.r_db.get_person_from_handle(person_handle) 1201 person_name = self.get_name(person) 1202 1203 # return addressbook hyperlink to its caller 1204 return Html("a", person_name, href=url, 1205 title=html_escape(person_name)) 1206 1207 def get_name(self, person, maiden_name=None): 1208 """ I5118 1209 1210 Return person's name, unless maiden_name given, unless married_name 1211 listed. 1212 1213 @param: person -- person object from database 1214 @param: maiden_name -- Female's family surname 1215 """ 1216 # get name format for displaying names 1217 name_format = self.report.options['name_format'] 1218 1219 # Get all of a person's names 1220 primary_name = person.get_primary_name() 1221 married_name = None 1222 names = [primary_name] + person.get_alternate_names() 1223 for name in names: 1224 if int(name.get_type()) == NameType.MARRIED: 1225 married_name = name 1226 break # use first 1227 1228 # Now, decide which to use: 1229 if maiden_name is not None: 1230 if married_name is not None: 1231 name = Name(married_name) 1232 else: 1233 name = Name(primary_name) 1234 surname_obj = name.get_primary_surname() 1235 surname_obj.set_surname(maiden_name) 1236 else: 1237 name = Name(primary_name) 1238 name.set_display_as(name_format) 1239 return _nd.display_name(name) 1240 1241 def display_attribute_header(self): 1242 """ 1243 Display the attribute section and its table header 1244 """ 1245 # begin attributes division and section title 1246 with Html("div", class_="subsection", id="attributes") as section: 1247 section += Html("h4", self._("Attributes"), inline=True) 1248 1249 # begin attributes table 1250 with Html("table", class_="infolist attrlist") as attrtable: 1251 section += attrtable 1252 1253 thead = Html("thead") 1254 attrtable += thead 1255 1256 trow = Html("tr") 1257 thead += trow 1258 1259 trow.extend( 1260 Html("th", label, class_=colclass, inline=True) 1261 for (label, colclass) in [ 1262 (self._("Type"), "ColumnType"), 1263 (self._("Value"), "ColumnValue"), 1264 (self._("Notes"), "ColumnNotes"), 1265 (self._("Sources"), "ColumnSources")] 1266 ) 1267 return section, attrtable 1268 1269 def display_attr_list(self, attrlist, 1270 attrtable): 1271 """ 1272 Will display a list of attributes 1273 1274 @param: attrlist -- a list of attributes 1275 @param: attrtable -- the table element that is being added to 1276 """ 1277 tbody = Html("tbody") 1278 attrtable += tbody 1279 1280 tbody.extend( 1281 self.dump_attribute(attr) for attr in attrlist 1282 ) 1283 1284 def write_footer(self, date): 1285 """ 1286 Will create and display the footer section of each page... 1287 1288 @param: bottom -- whether to specify location of footer section 1289 or not? 1290 """ 1291 # begin footer division 1292 with Html("div", id="footer") as footer: 1293 1294 footer_note = self.report.options['footernote'] 1295 if footer_note: 1296 note = self.get_note_format( 1297 self.r_db.get_note_from_gramps_id(footer_note), 1298 False 1299 ) 1300 user_footer = Html("div", id='user_footer') 1301 footer += user_footer 1302 1303 # attach note 1304 user_footer += note 1305 1306 msg = self._('Generated by %(gramps_home_html_start)s' 1307 'Gramps%(html_end)s %(version)s' 1308 ) % {'gramps_home_html_start' : 1309 '<a href="' + URL_HOMEPAGE + '">', 1310 'html_end' : '</a>', 1311 'version' : VERSION} 1312 if date is not None and date > 0: 1313 msg += "<br />" 1314 last_modif = datetime.datetime.fromtimestamp(date).strftime( 1315 '%Y-%m-%d %H:%M:%S') 1316 msg += self._('Last change was the %(date)s') % {'date' : 1317 last_modif} 1318 else: 1319 dat_txt = self._(' on %(date)s') 1320 msg += dat_txt % {'date' : self.rlocale.get_date(Today())} 1321 1322 origin1 = self.report.filter.get_name(self.rlocale) 1323 filt_number = self.report.options['filter'] 1324 # optional "link-home" feature; see bug report #2736 1325 if self.report.options['linkhome']: 1326 center_person = self.r_db.get_person_from_gramps_id( 1327 self.report.options['pid']) 1328 if (center_person and 1329 self.report.person_in_webreport(center_person.handle)): 1330 center_person_url = self.report.build_url_fname_html( 1331 center_person.handle, "ppl", self.uplink) 1332 1333 #person_name = self.get_name(center_person) 1334 if filt_number > 0 and filt_number < 5: 1335 subject_url = '<a href="' + center_person_url + '">' 1336 subject_url += origin1 + '</a>' 1337 else: 1338 subject_url = origin1 1339 msg += self._( 1340 '%(http_break)sCreated for %(subject_url)s') % { 1341 'http_break' : '<br />', 1342 'subject_url' : subject_url} 1343 else: 1344 msg += self._( 1345 '%(http_break)sCreated for %(subject_url)s') % { 1346 'http_break' : '<br />', 1347 'subject_url' : origin1} 1348 1349 # creation author 1350 footer += Html("p", msg, id='createdate') 1351 1352 # get copyright license for all pages 1353 copy_nr = self.report.copyright 1354 1355 text = '' 1356 if copy_nr == 0: 1357 if self.author: 1358 year = Today().get_year() 1359 text = '© %(year)d %(person)s' % { 1360 'person' : self.author, 'year' : year} 1361 elif copy_nr < len(_CC): 1362 # Note. This is a URL 1363 fname = "/".join(["images", "somerights20.gif"]) 1364 url = self.report.build_url_fname(fname, None, self.uplink) 1365 text = _CC[copy_nr] % {'gif_fname' : url} 1366 footer += Html("p", text, id='copyright') 1367 1368 # return footer to its callers 1369 return footer 1370 1371 def write_header(self, title): 1372 """ 1373 Note. 'title' is used as currentsection in the navigation links and 1374 as part of the header title. 1375 1376 @param: title -- Is the title of the web page 1377 """ 1378 # begin each html page... 1379 xmllang = xml_lang() 1380 page, head, body = Html.page('%s - %s' % 1381 (html_escape(self.title_str.strip()), 1382 html_escape(title)), 1383 self.report.encoding, 1384 xmllang, cms=self.usecms) 1385 1386 # temporary fix for .php parsing error 1387 if self.ext in [".php", ".php3", ".cgi"]: 1388 del page[0] 1389 1390 # Header constants 1391 _meta1 = 'name ="viewport" content="width=device-width; ' 1392 _meta1 += 'height=device-height; initial-scale=1.0; ' 1393 _meta1 += 'minimum-scale=0.5; maximum-scale=10.0; user-scalable=yes"' 1394 _meta2 = 'name ="apple-mobile-web-app-capable" content="yes"' 1395 _meta3 = 'name="generator" content="%s %s %s"' % ( 1396 PROGRAM_NAME, VERSION, URL_HOMEPAGE) 1397 _meta4 = 'name="author" content="%s"' % self.author 1398 1399 # create additional meta tags 1400 meta = Html("meta", attr=_meta1) + ( 1401 Html("meta", attr=_meta2, indent=False), 1402 Html("meta", attr=_meta3, indent=False), 1403 Html("meta", attr=_meta4, indent=False) 1404 ) 1405 1406 # Link to _NARRATIVESCREEN stylesheet 1407 fname = "/".join(["css", _NARRATIVESCREEN]) 1408 url2 = self.report.build_url_fname(fname, None, self.uplink) 1409 1410 # Link to _NARRATIVEPRINT stylesheet 1411 fname = "/".join(["css", _NARRATIVEPRINT]) 1412 url3 = self.report.build_url_fname(fname, None, self.uplink) 1413 1414 # Link to Gramps favicon 1415 fname = "/".join(['images', 'favicon2.ico']) 1416 url4 = self.report.build_url_image("favicon2.ico", 1417 "images", self.uplink) 1418 1419 # create stylesheet and favicon links 1420 links = Html("link", type="image/x-icon", 1421 href=url4, rel="shortcut icon") + ( 1422 Html("link", type="text/css", href=url3, 1423 media='print', rel="stylesheet", indent=False), 1424 Html("link", type="text/css", href=url2, 1425 media="screen", rel="stylesheet", indent=False), 1426 ) 1427 1428 # Link to Navigation Menus stylesheet 1429 if CSS[self.report.css]["navigation"]: 1430 fname = "/".join(["css", "narrative-menus.css"]) 1431 url = self.report.build_url_fname(fname, None, self.uplink) 1432 links += Html("link", type="text/css", href=url, 1433 media="screen", rel="stylesheet", indent=False) 1434 1435 # add additional meta and link tags 1436 head += meta 1437 head += links 1438 1439 # Add the script to control the menu 1440 menuscript = Html("<script>function navFunction() { " 1441 "var x = document.getElementById(\"dropmenu\"); " 1442 "if (x.className === \"nav\") { x.className += \"" 1443 " responsive\"; } else { x.className = \"nav\"; }" 1444 " }</script>") 1445 head += menuscript 1446 1447 # add outerwrapper to set the overall page width 1448 outerwrapperdiv = Html("div", id='outerwrapper') 1449 body += outerwrapperdiv 1450 1451 # begin header section 1452 #headerdiv = Html("div", id='header') + ( 1453 headerdiv = Html("div", id='header') + ( 1454 Html("<a href=\"javascript:void(0);\" class=\"navIcon\"" 1455 " onclick=\"navFunction()\">≡</a>")) + ( 1456 Html("h1", html_escape(self.title_str), 1457 id="SiteTitle", inline=True) 1458 ) 1459 outerwrapperdiv += headerdiv 1460 1461 header_note = self.report.options['headernote'] 1462 if header_note: 1463 note = self.get_note_format( 1464 self.r_db.get_note_from_gramps_id(header_note), 1465 False) 1466 1467 user_header = Html("div", id='user_header') 1468 headerdiv += user_header 1469 1470 # attach note 1471 user_header += note 1472 1473 # Begin Navigation Menu-- 1474 # is the style sheet either Basic-Blue or Visually Impaired, 1475 # and menu layout is Drop Down? 1476 if (self.report.css == _("Basic-Blue") or 1477 self.report.css == _("Visually Impaired") 1478 ) and self.report.navigation == "dropdown": 1479 outerwrapperdiv += self.display_drop_menu() 1480 else: 1481 outerwrapperdiv += self.display_nav_links(title) 1482 1483 # message for Codacy : 1484 # body is used in some modules to add functions like onload(), 1485 # initialize(), ... 1486 # some modules doesn't need that, so body is an unused variable 1487 # in these modules. 1488 # return page, head, and body to its classes... 1489 return page, head, body, outerwrapperdiv 1490 1491 def display_nav_links(self, currentsection): 1492 """ 1493 Creates the navigation menu 1494 1495 @param: currentsection = which menu item are you on 1496 """ 1497 # include repositories or not? 1498 inc_repos = True 1499 if (not self.report.inc_repository or 1500 not self.r_db.get_repository_handles()): 1501 inc_repos = False 1502 1503 # create media pages... 1504 _create_media_link = False 1505 if self.create_media: 1506 _create_media_link = True 1507 if self.create_thumbs_only: 1508 _create_media_link = False 1509 1510 # create link to web calendar pages... 1511 #_create_calendar_link = False 1512 if self.usecal: 1513 #_create_calendar_link = True 1514 self.target_cal_uri += "/index" 1515 1516 # Determine which menu items will be available? 1517 # Menu items have been adjusted to concide with Gramps Navigation 1518 # Sidebar order... 1519 1520 navs = [ 1521 (self.report.index_fname, self._("Html|Home"), 1522 self.report.use_home), 1523 (self.report.intro_fname, self._("Introduction"), 1524 self.report.use_intro), 1525 (self.report.extrapage, self.extrapagename, (self.extrapage != "")), 1526 ('individuals', self._("Individuals"), True), 1527 (self.report.surname_fname, self._("Surnames"), True), 1528 ('families', self._("Families"), self.report.inc_families), 1529 ('events', self._("Events"), self.report.inc_events), 1530 ('places', self._("Places"), self.report.inc_places), 1531 ('sources', self._("Sources"), self.report.inc_sources), 1532 ('repositories', self._("Repositories"), inc_repos), 1533 ('media', self._("Media"), _create_media_link), 1534 ('thumbnails', self._("Thumbnails"), self.create_media), 1535 ('download', self._("Download"), self.report.inc_download), 1536 ("addressbook", self._("Address Book"), 1537 self.report.inc_addressbook), 1538 ('contact', self._("Contact"), self.report.use_contact), 1539 ('statistics', self._("Statistics"), self.report.inc_stats), 1540 (self.target_cal_uri, self._("Web Calendar"), self.usecal) 1541 ] 1542 1543 # Remove menu sections if they are not being created? 1544 navs = ((url_text, nav_text) 1545 for url_text, nav_text, cond in navs if cond) 1546 menu_items = [[url, text] for url, text in navs] 1547 number_items = len(menu_items) 1548 1549 # begin navigation menu division... 1550 with Html("div", class_="wrappernav", 1551 id="nav", role="navigation") as navigation: 1552 with Html("div", class_="container") as container: 1553 1554 index = 0 1555 unordered = Html("ul", class_="nav", id="dropmenu") 1556 while index < number_items: 1557 url_fname, nav_text = menu_items[index] 1558 hyper = self.get_nav_menu_hyperlink(url_fname, nav_text) 1559 1560 # Define 'currentsection' to correctly set navlink item 1561 # CSS id 'CurrentSection' for Navigation styling. 1562 # Use 'self.report.cur_fname' to determine 1563 # 'CurrentSection' for individual elements for 1564 # Navigation styling. 1565 1566 # Figure out if we need <li class = "CurrentSection"> 1567 # or just <li> 1568 1569 check_cs = False 1570 if nav_text == currentsection: 1571 check_cs = True 1572 elif nav_text == _("Surnames"): 1573 if "srn" in self.report.cur_fname: 1574 check_cs = True 1575 elif _("Surnames") in currentsection: 1576 check_cs = True 1577 elif nav_text == _("Individuals"): 1578 if "ppl" in self.report.cur_fname: 1579 check_cs = True 1580 elif nav_text == _("Families"): 1581 if "fam" in self.report.cur_fname: 1582 check_cs = True 1583 elif nav_text == _("Sources"): 1584 if "src" in self.report.cur_fname: 1585 check_cs = True 1586 elif nav_text == _("Places"): 1587 if "plc" in self.report.cur_fname: 1588 check_cs = True 1589 elif nav_text == _("Events"): 1590 if "evt" in self.report.cur_fname: 1591 check_cs = True 1592 elif nav_text == _("Media"): 1593 if "img" in self.report.cur_fname: 1594 check_cs = True 1595 elif nav_text == _("Address Book"): 1596 if "addr" in self.report.cur_fname: 1597 check_cs = True 1598 temp_cs = 'class = "CurrentSection"' 1599 check_cs = temp_cs if check_cs else False 1600 if check_cs: 1601 unordered.extend( 1602 Html("li", hyper, attr=check_cs, inline=True) 1603 ) 1604 else: 1605 unordered.extend( 1606 Html("li", hyper, inline=True) 1607 ) 1608 index += 1 1609 1610 if self.prevnext: 1611 prv = Html('<a onclick="history.go(-1);">%s</a>' % 1612 self._("Previous")) 1613 nxt = Html('<a onclick="history.go(+1);">%s</a>' % 1614 self._("Next")) 1615 unordered.extend(Html("li", prv, inline=True)) 1616 unordered.extend(Html("li", nxt, inline=True)) 1617 container += unordered 1618 navigation += container 1619 return navigation 1620 1621 def display_drop_menu(self): 1622 """ 1623 Creates the Drop Down Navigation Menu 1624 """ 1625 # include repositories or not? 1626 inc_repos = True 1627 if (not self.report.inc_repository or 1628 not self.r_db.get_repository_handles()): 1629 inc_repos = False 1630 1631 # create media pages... 1632 _create_media_link = False 1633 if self.create_media: 1634 _create_media_link = True 1635 if self.create_thumbs_only: 1636 _create_media_link = False 1637 1638 personal = [ 1639 (self.report.intro_fname, self._("Introduction"), 1640 self.report.use_intro), 1641 ("individuals", self._("Individuals"), True), 1642 (self.report.surname_fname, self._("Surnames"), True), 1643 ("families", self._("Families"), self.report.inc_families) 1644 ] 1645 personal = ((url_text, nav_text) 1646 for url_text, nav_text, cond in personal if cond) 1647 personal = [[url, text] for url, text in personal] 1648 1649 navs1 = [ 1650 ("events", self._("Events"), self.report.inc_events), 1651 ("places", self._("Places"), True), 1652 ("sources", self._("Sources"), True), 1653 ("repositories", self._("Repositories"), inc_repos) 1654 ] 1655 navs1 = ((url_text, nav_text) 1656 for url_text, nav_text, cond in navs1 if cond) 1657 navs1 = [[url, text] for url, text in navs1] 1658 1659 media = [ 1660 ("media", self._("Media"), _create_media_link), 1661 ("thumbnails", self._("Thumbnails"), True) 1662 ] 1663 media = ((url_text, nav_text) 1664 for url_text, nav_text, cond in media if cond) 1665 media = [[url, text] for url, text in media] 1666 1667 misc = [ 1668 ('download', self._("Download"), self.report.inc_download), 1669 ("addressbook", self._("Address Book"), self.report.inc_addressbook) 1670 ] 1671 misc = ((url_text, nav_text) 1672 for url_text, nav_text, cond in misc if cond) 1673 misc = [[url, text] for url, text in misc] 1674 1675 contact = [ 1676 ('contact', self._("Contact"), self.report.use_contact) 1677 ] 1678 contact = ((url_text, nav_text) 1679 for url_text, nav_text, cond in contact if cond) 1680 contact = [[url, text] for url, text in contact] 1681 1682 # begin navigation menu division... 1683 with Html("div", class_="wrapper", 1684 id="nav", role="navigation") as navigation: 1685 with Html("div", class_="container") as container: 1686 unordered = Html("ul", class_="menu", id="dropmenu") 1687 1688 if self.report.use_home: 1689 list_html = Html("li", 1690 self.get_nav_menu_hyperlink( 1691 self.report.index_fname, 1692 self._("Html|Home"))) 1693 unordered += list_html 1694 1695 # add personal column 1696 self.get_column_data(unordered, personal, self._("Personal")) 1697 1698 if navs1: 1699 for url_fname, nav_text in navs1: 1700 unordered.extend( 1701 Html("li", self.get_nav_menu_hyperlink(url_fname, 1702 nav_text), 1703 inline=True) 1704 ) 1705 1706 # add media column 1707 self.get_column_data(unordered, media, self._("Media")) 1708 1709 # add miscellaneous column 1710 self.get_column_data(unordered, misc, self._("Miscellaneous")) 1711 1712 # add contact column 1713 self.get_column_data(unordered, contact, _("Contact")) 1714 1715 container += unordered 1716 navigation += container 1717 return navigation 1718 1719 def add_image(self, option_name, head, height=0): 1720 """ 1721 Will add an image (if present) to the page 1722 If this image contains regions, try to add them. 1723 1724 @param: option_name -- The name of the report option 1725 @param: height -- Height of the image 1726 """ 1727 pic_id = self.report.options[option_name] 1728 if pic_id: 1729 obj = self.r_db.get_media_from_gramps_id(pic_id) 1730 if obj is None: 1731 return None 1732 # get media rectangles 1733 _region_items = self.media_ref_rect_regions(obj.get_handle(), 1734 linkurl=self.uplink) 1735 1736 # if there are media rectangle regions, attach behaviour style sheet 1737 if _region_items: 1738 fname = "/".join(["css", "behaviour.css"]) 1739 url = self.report.build_url_fname(fname, None, self.uplink) 1740 head += Html("link", href=url, type="text/css", 1741 media="screen", rel="stylesheet") 1742 mime_type = obj.get_mime_type() 1743 if mime_type and mime_type.startswith("image"): 1744 try: 1745 1746 newpath, dummy_tpath = self.report.prepare_copy_media(obj) 1747 self.report.copy_file(media_path_full( 1748 self.r_db, obj.get_path()), newpath) 1749 1750 # begin image 1751 with Html("div", id="GalleryDisplay", 1752 style='width: auto; height: auto') as image: 1753 if _region_items: 1754 # add all regions and links to persons 1755 regions = Html("ol", class_="RegionBox") 1756 while _region_items: 1757 (name, coord_x, coord_y, 1758 width, height, linkurl 1759 ) = _region_items.pop() 1760 regions += Html( 1761 "li", 1762 style="left:%d%%; " 1763 "top:%d%%; " 1764 "width:%d%%; " 1765 "height:%d%%;" % ( 1766 coord_x, coord_y, 1767 width, height)) + ( 1768 Html("a", name, 1769 href=linkurl) 1770 ) 1771 image += regions 1772 1773 # add image 1774 imag = Html("img") 1775 imag.attr = '' 1776 if height: 1777 imag.attr += 'height = "%d"' % height 1778 1779 descr = html_escape(obj.get_description()) 1780 newpath = self.report.build_url_fname(newpath) 1781 imag.attr += ' src = "%s" alt = "%s"' % (newpath, descr) 1782 fname = self.report.build_url_fname(obj.get_handle(), 1783 "img", 1784 False) + self.ext 1785 #image += imag 1786 inc_gallery = self.report.options['gallery'] 1787 if not self.create_thumbs_only and inc_gallery: 1788 img_link = Html("a", href=fname, title=descr) + ( 1789 Html("img", src=newpath, alt=descr)) 1790 else: 1791 # We can't show the image html page. 1792 # This page doesn't exist. 1793 img_link = Html("img", src=newpath, alt=descr) 1794 image += img_link 1795 1796 return image 1797 1798 except (IOError, OSError) as msg: 1799 self.r_user.warn(_("Could not add photo to page"), 1800 str(msg)) 1801 1802 # no image to return 1803 return None 1804 1805 def media_ref_rect_regions(self, handle, linkurl=True): 1806 """ 1807 Gramps feature #2634 -- attempt to highlight subregions in media 1808 objects and link back to the relevant web page. 1809 1810 This next section of code builds up the "records" we'll need to 1811 generate the html/css code to support the subregions 1812 1813 @param: handle -- The media handle to use 1814 """ 1815 # get all of the backlinks to this media object; meaning all of 1816 # the people, events, places, etc..., that use this image 1817 _region_items = set() 1818 for (classname, newhandle) in self.r_db.find_backlink_handles( 1819 handle, 1820 include_classes=["Person", "Family", "Event", "Place"]): 1821 1822 # for each of the backlinks, get the relevant object from the db 1823 # and determine a few important things, such as a text name we 1824 # can use, and the URL to a relevant web page 1825 _obj = None 1826 _name = "" 1827 _linkurl = "#" 1828 if classname == "Person": 1829 # Is this a person for whom we have built a page: 1830 if self.report.person_in_webreport(newhandle): 1831 # If so, let's add a link to them: 1832 _obj = self.r_db.get_person_from_handle(newhandle) 1833 if _obj: 1834 # What is the shortest possible name we could use 1835 # for this person? 1836 _name = (_obj.get_primary_name().get_call_name() or 1837 _obj.get_primary_name().get_first_name() or 1838 self._("Unknown") 1839 ) 1840 _linkurl = self.report.build_url_fname_html(_obj.handle, 1841 "ppl", 1842 linkurl) 1843 elif classname == "Family" and self.inc_families: 1844 _obj = self.r_db.get_family_from_handle(newhandle) 1845 partner1_handle = _obj.get_father_handle() 1846 partner2_handle = _obj.get_mother_handle() 1847 partner1 = None 1848 partner2 = None 1849 if partner1_handle: 1850 partner1 = self.r_db.get_person_from_handle( 1851 partner1_handle) 1852 if partner2_handle: 1853 partner2 = self.r_db.get_person_from_handle( 1854 partner2_handle) 1855 if partner2 and partner1: 1856 _name = partner1.get_primary_name().get_first_name() 1857 _linkurl = self.report.build_url_fname_html(partner1_handle, 1858 "ppl", True) 1859 elif partner1: 1860 _name = partner1.get_primary_name().get_first_name() 1861 _linkurl = self.report.build_url_fname_html(partner1_handle, 1862 "ppl", True) 1863 elif partner2: 1864 _name = partner2.get_primary_name().get_first_name() 1865 _linkurl = self.report.build_url_fname_html(partner2_handle, 1866 "ppl", True) 1867 if not _name: 1868 _name = self._("Unknown") 1869 elif classname == "Event" and self.inc_events: 1870 _obj = self.r_db.get_event_from_handle(newhandle) 1871 _name = _obj.get_description() 1872 if not _name: 1873 _name = self._("Unknown") 1874 _linkurl = self.report.build_url_fname_html(_obj.handle, 1875 "evt", True) 1876 elif classname == "Place": 1877 _obj = self.r_db.get_place_from_handle(newhandle) 1878 _name = _pd.display(self.r_db, _obj) 1879 if not _name: 1880 _name = self._("Unknown") 1881 _linkurl = self.report.build_url_fname_html(newhandle, 1882 "plc", True) 1883 1884 # continue looking through the loop for an object... 1885 if _obj is None: 1886 continue 1887 1888 # get a list of all media refs for this object 1889 media_list = _obj.get_media_list() 1890 1891 # go media refs looking for one that points to this image 1892 for mediaref in media_list: 1893 1894 # is this mediaref for this image? do we have a rect? 1895 if mediaref.ref == handle and mediaref.rect is not None: 1896 1897 (coord_x1, coord_y1, coord_x2, coord_y2) = mediaref.rect 1898 # Gramps gives us absolute coordinates, 1899 # but we need relative width + height 1900 width = coord_x2 - coord_x1 1901 height = coord_y2 - coord_y1 1902 1903 # remember all this information, cause we'll need 1904 # need it later when we output the <li>...</li> tags 1905 item = (_name, coord_x1, coord_y1, width, height, _linkurl) 1906 _region_items.add(item) 1907 1908 # End of code that looks for and prepares the media object regions 1909 1910 return sorted(_region_items) 1911 1912 def media_ref_region_to_object(self, media_handle, obj): 1913 """ 1914 Return a region of this image if it refers to this object. 1915 1916 @param: media_handle -- The media handle to use 1917 @param: obj -- The object reference 1918 """ 1919 # get a list of all media refs for this object 1920 for mediaref in obj.get_media_list(): 1921 # is this mediaref for this image? do we have a rect? 1922 if (mediaref.ref == media_handle and 1923 mediaref.rect is not None): 1924 return mediaref.rect # (x1, y1, x2, y2) 1925 return None 1926 1927 def disp_first_img_as_thumbnail(self, photolist, object_): 1928 """ 1929 Return the Html of the first image of photolist that is 1930 associated with object. First image might be a region in an 1931 image. Or, the first image might have regions defined in it. 1932 1933 @param: photolist -- The list of media 1934 @param: object_ -- The object reference 1935 """ 1936 if not photolist or not self.create_media: 1937 return None 1938 1939 photo_handle = photolist[0].get_reference_handle() 1940 photo = self.r_db.get_media_from_handle(photo_handle) 1941 mime_type = photo.get_mime_type() 1942 descr = photo.get_description() 1943 1944 # begin snapshot division 1945 with Html("div", class_="snapshot") as snapshot: 1946 1947 if mime_type: 1948 1949 region = self.media_ref_region_to_object(photo_handle, object_) 1950 if region: 1951 1952 # make a thumbnail of this region 1953 newpath = self.copy_thumbnail(photo_handle, photo, region) 1954 newpath = self.report.build_url_fname(newpath, uplink=True) 1955 snapshot += self.media_link(photo_handle, newpath, descr, 1956 uplink=self.uplink, 1957 usedescr=False) 1958 else: 1959 dummy_rpath, newpath = self.report.prepare_copy_media(photo) 1960 newpath = self.report.build_url_fname(newpath, uplink=True) 1961 snapshot += self.media_link(photo_handle, newpath, 1962 descr, 1963 uplink=self.uplink, 1964 usedescr=False) 1965 else: 1966 # begin hyperlink 1967 snapshot += self.doc_link(photo_handle, descr, 1968 uplink=self.uplink, usedescr=False) 1969 1970 # return snapshot division to its callers 1971 return snapshot 1972 1973 def disp_add_img_as_gallery(self, photolist, object_): 1974 """ 1975 Display additional image as gallery 1976 1977 @param: photolist -- The list of media 1978 @param: object_ -- The object reference 1979 """ 1980 if not photolist or not self.create_media: 1981 return None 1982 1983 # make referenced images have the same order as in media list: 1984 photolist_handles = {} 1985 for mediaref in photolist: 1986 photolist_handles[mediaref.get_reference_handle()] = mediaref 1987 photolist_ordered = [] 1988 for photoref in copy.copy(object_.get_media_list()): 1989 if photoref.ref in photolist_handles: 1990 photo = photolist_handles[photoref.ref] 1991 photolist_ordered.append(photo) 1992 # and add any that are left (should there be any?) 1993 photolist_ordered += photolist 1994 1995 # begin individualgallery division and section title 1996 with Html("div", class_="subsection", id="indivgallery") as section: 1997 section += Html("h4", self._("Media"), inline=True) 1998 1999 displayed = [] 2000 for mediaref in photolist_ordered: 2001 2002 photo_handle = mediaref.get_reference_handle() 2003 photo = self.r_db.get_media_from_handle(photo_handle) 2004 2005 if photo_handle in displayed: 2006 continue 2007 mime_type = photo.get_mime_type() 2008 2009 # get media description 2010 descr = photo.get_description() 2011 2012 if mime_type: 2013 try: 2014 # create thumbnail url 2015 # extension needs to be added as it is not already there 2016 url = self.report.build_url_fname(photo_handle, "thumb", 2017 True) + ".png" 2018 # begin hyperlink 2019 section += self.media_link(photo_handle, url, 2020 descr, uplink=self.uplink, 2021 usedescr=True) 2022 except (IOError, OSError) as msg: 2023 self.r_user.warn(_("Could not add photo to page"), 2024 str(msg)) 2025 else: 2026 try: 2027 # begin hyperlink 2028 section += self.doc_link(photo_handle, descr, 2029 uplink=self.uplink) 2030 except (IOError, OSError) as msg: 2031 self.r_user.warn(_("Could not add photo to page"), 2032 str(msg)) 2033 displayed.append(photo_handle) 2034 2035 # add fullclear for proper styling 2036 section += FULLCLEAR 2037 2038 # return indivgallery division to its caller 2039 return section 2040 2041 def display_note_list(self, notelist=None): 2042 """ 2043 Display note list 2044 2045 @param: notelist -- The list of notes 2046 """ 2047 if not notelist: 2048 return None 2049 2050 # begin narrative division 2051 with Html("div", class_="subsection narrative") as section: 2052 2053 for notehandle in notelist: 2054 note = self.r_db.get_note_from_handle(notehandle) 2055 2056 if note: 2057 note_text = self.get_note_format(note, True) 2058 2059 # add section title 2060 section += Html("h4", self._("Narrative"), inline=True) 2061 2062 # attach note 2063 section += note_text 2064 2065 # return notes to its callers 2066 return section 2067 2068 def display_url_list(self, urllist=None): 2069 """ 2070 Display URL list 2071 2072 @param: urllist -- The list of urls 2073 """ 2074 if not urllist: 2075 return None 2076 2077 # begin web links division 2078 with Html("div", class_="subsection", id="WebLinks") as section: 2079 section += Html("h4", self._("Web Links"), inline=True) 2080 2081 with Html("table", class_="infolist weblinks") as table: 2082 section += table 2083 2084 thead = Html("thead") 2085 table += thead 2086 2087 trow = Html("tr") 2088 thead += trow 2089 2090 trow.extend(Html('th', label, class_=colclass, inline=True) 2091 for (label, colclass) in [ 2092 (self._("Type"), "ColumnType"), 2093 (self._("Description"), "ColumnDescription")] 2094 ) 2095 2096 tbody = Html("tbody") 2097 table += tbody 2098 2099 for url in urllist: 2100 2101 trow = Html("tr") 2102 tbody += trow 2103 2104 _type = self._(url.get_type().xml_str()) 2105 uri = url.get_path() 2106 descr = url.get_description() 2107 2108 # Email address 2109 if _type == UrlType.EMAIL: 2110 if not uri.startswith("mailto:"): 2111 uri = "mailto:%(email)s" % {'email' : uri} 2112 2113 # Web Site address 2114 elif _type == UrlType.WEB_HOME: 2115 if not (uri.startswith("http://") or 2116 uri.startswith("https://")): 2117 url = self.secure_mode 2118 uri = url + "%(website)s" % {"website" : uri} 2119 2120 # FTP server address 2121 elif _type == UrlType.WEB_FTP: 2122 if not (uri.startswith("ftp://") or 2123 uri.startswith("ftps://")): 2124 uri = "ftp://%(ftpsite)s" % {"ftpsite" : uri} 2125 2126 descr = Html("p", html_escape(descr)) + ( 2127 Html("a", self._(" [Click to Go]"), href=uri, title=uri) 2128 ) 2129 2130 trow.extend( 2131 Html("td", data, class_=colclass, inline=True) 2132 for (data, colclass) in [ 2133 (str(_type), "ColumnType"), 2134 (descr, "ColumnDescription") 2135 ] 2136 ) 2137 return section 2138 2139 def display_lds_ordinance(self, db_obj_): 2140 """ 2141 Display LDS information for a person or family 2142 2143 @param: db_obj_ -- The database object 2144 """ 2145 ldsordlist = db_obj_.lds_ord_list 2146 if not ldsordlist: 2147 return None 2148 2149 # begin LDS Ordinance division and section title 2150 with Html("div", class_="subsection", id="LDSOrdinance") as section: 2151 section += Html("h4", _("Latter-Day Saints/ LDS Ordinance"), 2152 inline=True) 2153 2154 # ump individual LDS ordinance list 2155 section += self.dump_ordinance(db_obj_, "Person") 2156 2157 # return section to its caller 2158 return section 2159 2160 def display_ind_sources(self, srcobj): 2161 """ 2162 Will create the "Source References" section for an object 2163 2164 @param: srcobj -- Sources object 2165 """ 2166 list(map( 2167 lambda i: self.bibli.add_reference( 2168 self.r_db.get_citation_from_handle(i)), 2169 srcobj.get_citation_list())) 2170 sourcerefs = self.display_source_refs(self.bibli) 2171 2172 # return to its callers 2173 return sourcerefs 2174 2175 # Only used in IndividualPage.display_ind_sources(), 2176 # and MediaPage.display_media_sources() 2177 def display_source_refs(self, bibli): 2178 """ 2179 Display source references 2180 2181 @param: bibli -- List of sources 2182 """ 2183 if bibli.get_citation_count() == 0: 2184 return None 2185 2186 with Html("div", class_="subsection", id="sourcerefs") as section: 2187 section += Html("h4", self._("Source References"), inline=True) 2188 2189 ordered = Html("ol") 2190 2191 cindex = 0 2192 citationlist = bibli.get_citation_list() 2193 for citation in citationlist: 2194 cindex += 1 2195 # Add this source and its references to the page 2196 source = self.r_db.get_source_from_handle( 2197 citation.get_source_handle()) 2198 if source is not None: 2199 if source.get_author(): 2200 authorstring = source.get_author() + ": " 2201 else: 2202 authorstring = "" 2203 list_html = Html("li", 2204 self.source_link( 2205 source.get_handle(), 2206 authorstring + source.get_title(), 2207 source.get_gramps_id(), cindex, 2208 uplink=self.uplink)) 2209 else: 2210 list_html = Html("li", "None") 2211 2212 ordered1 = Html("ol") 2213 citation_ref_list = citation.get_ref_list() 2214 for key, sref in citation_ref_list: 2215 cit_ref_li = Html("li", id="sref%d%s" % (cindex, key)) 2216 tmp = Html("ul") 2217 conf = conf_strings.get(sref.confidence, self._('Unknown')) 2218 if conf == conf_strings[Citation.CONF_NORMAL]: 2219 conf = None 2220 else: 2221 conf = self._(conf) 2222 for (label, data) in [[self._("Date"), 2223 self.rlocale.get_date(sref.date)], 2224 [self._("Page"), sref.page], 2225 [self._("Confidence"), conf]]: 2226 if data: 2227 tmp += Html("li", 2228 _("%(str1)s: %(str2)s") % { 2229 'str1' : label, 2230 'str2' : data 2231 }) 2232 if self.create_media: 2233 for media_ref in sref.get_media_list(): 2234 media_handle = media_ref.get_reference_handle() 2235 media = self.r_db.get_media_from_handle( 2236 media_handle) 2237 if media: 2238 mime_type = media.get_mime_type() 2239 if mime_type: 2240 if mime_type.startswith("image/"): 2241 real_path, new_path = \ 2242 self.report.prepare_copy_media( 2243 media) 2244 newpath = self.report.build_url_fname( 2245 new_path, uplink=self.uplink) 2246 self.report.copy_file( 2247 media_path_full(self.r_db, 2248 media.get_path()), 2249 real_path) 2250 2251 tmp += Html("li", 2252 self.media_link( 2253 media_handle, 2254 newpath, 2255 media.get_description(), 2256 self.uplink, 2257 usedescr=False), 2258 inline=True) 2259 2260 else: 2261 tmp += Html("li", 2262 self.doc_link( 2263 media_handle, 2264 media.get_description(), 2265 self.uplink, 2266 usedescr=False), 2267 inline=True) 2268 for handle in sref.get_note_list(): 2269 this_note = self.r_db.get_note_from_handle(handle) 2270 if this_note is not None: 2271 note_format = self.get_note_format(this_note, True) 2272 tmp += Html("li", 2273 _("%(str1)s: %(str2)s") % { 2274 'str1' : str(this_note.get_type()), 2275 'str2' : note_format 2276 }) 2277 if tmp: 2278 cit_ref_li += tmp 2279 ordered1 += cit_ref_li 2280 2281 if citation_ref_list: 2282 list_html += ordered1 2283 ordered += list_html 2284 section += ordered 2285 2286 # return section to its caller 2287 return section 2288 2289 def family_map_link(self, handle, url): 2290 """ 2291 Creates a link to the family map 2292 2293 @param: handle -- The family handle 2294 @param: url -- url to be linked 2295 """ 2296 dummy_handle = handle 2297 return Html("a", self._("Family Map"), href=url, 2298 title=self._("Family Map"), class_="familymap", inline=True) 2299 2300 def display_spouse(self, partner, family, place_lat_long): 2301 """ 2302 Display an individual's partner 2303 2304 @param: partner -- The partner 2305 @param: family -- The family 2306 @param: place_lat_long -- For use in Family Map Pages. This will be 2307 None if called from Family pages, which do 2308 not create a Family Map 2309 """ 2310 gender = partner.get_gender() 2311 reltype = family.get_relationship() 2312 2313 rtype = self._(str(family.get_relationship().xml_str())) 2314 2315 if reltype == FamilyRelType.MARRIED: 2316 if gender == Person.FEMALE: 2317 relstr = self._("Wife") 2318 elif gender == Person.MALE: 2319 relstr = self._("Husband") 2320 else: 2321 relstr = self._("Partner") 2322 else: 2323 relstr = self._("Partner") 2324 2325 # display family relationship status, and add spouse to FamilyMapPages 2326 if self.familymappages: 2327 self._get_event_place(partner, place_lat_long) 2328 2329 trow = Html("tr", class_="BeginFamily") + ( 2330 Html("td", rtype, class_="ColumnType", inline=True), 2331 Html("td", relstr, class_="ColumnAttribute", inline=True) 2332 ) 2333 2334 tcell = Html("td", class_="ColumnValue") 2335 trow += tcell 2336 2337 tcell += self.new_person_link(partner.get_handle(), uplink=True, 2338 person=partner) 2339 birth = death = "" 2340 bd_event = get_birth_or_fallback(self.r_db, partner) 2341 if bd_event: 2342 birth = self.rlocale.get_date(bd_event.get_date_object()) 2343 dd_event = get_death_or_fallback(self.r_db, partner) 2344 if dd_event: 2345 death = self.rlocale.get_date(dd_event.get_date_object()) 2346 2347 if death == "": 2348 death = "..." 2349 tcell += " ( * ", birth, " + ", death, " )" 2350 2351 return trow 2352 2353 def display_child_link(self, chandle): 2354 """ 2355 display child link ... 2356 2357 @param: chandle -- Child handle 2358 """ 2359 return self.new_person_link(chandle, uplink=True) 2360 2361 def new_person_link(self, person_handle, uplink=False, person=None, 2362 name_style=_NAME_STYLE_DEFAULT): 2363 """ 2364 creates a link for a person. If a page is generated for the person, a 2365 hyperlink is created, else just the name of the person. The returned 2366 vale will be an Html object if a hyperlink is generated, otherwise 2367 just a string 2368 2369 @param: person_handle -- Person in database 2370 @param: uplink -- If True, then "../../../" is inserted in 2371 front of the result 2372 @param: person -- Person object. This does not need to be 2373 passed. It should be passed if the person 2374 object has already been retrieved, as it 2375 will be used to improve performance 2376 """ 2377 result = self.report.obj_dict.get(Person).get(person_handle) 2378 2379 # construct link, name and gid 2380 if result is None: 2381 # The person is not included in the webreport 2382 link = "" 2383 if person is None: 2384 person = self.r_db.get_person_from_handle(person_handle) 2385 if person: 2386 name = self.report.get_person_name(person) 2387 gid = person.get_gramps_id() 2388 else: 2389 name = _("Unknown") 2390 gid = "" 2391 else: 2392 # The person has been encountered in the web report, but this does 2393 # not necessarily mean that a page has been generated 2394 (link, name, gid) = result 2395 2396 name = html_escape(name) 2397 # construct the result 2398 if not self.noid and gid != "": 2399 gid_html = Html("span", " [%s]" % gid, class_="grampsid", 2400 inline=True) 2401 else: 2402 gid_html = "" 2403 2404 if link != "": 2405 url = self.report.build_url_fname(link, uplink=uplink) 2406 hyper = Html("a", name, gid_html, href=url, inline=True) 2407 else: 2408 hyper = name + str(gid_html) 2409 2410 return hyper 2411 2412 def media_link(self, media_handle, img_url, name, 2413 uplink=False, usedescr=True): 2414 """ 2415 creates and returns a hyperlink to the thumbnail image 2416 2417 @param: media_handle -- Photo handle from report database 2418 @param: img_url -- Thumbnail url 2419 @param: name -- Photo description 2420 @param: uplink -- If True, then "../../../" is inserted in front 2421 of the result. 2422 @param: usedescr -- Add media description 2423 """ 2424 url = self.report.build_url_fname_html(media_handle, "img", uplink) 2425 name = html_escape(name) 2426 2427 # begin thumbnail division 2428 with Html("div", class_="thumbnail") as thumbnail: 2429 2430 # begin hyperlink 2431 if not self.create_thumbs_only: 2432 hyper = Html("a", href=url, title=name) + ( 2433 Html("img", src=img_url, alt=name) 2434 ) 2435 else: 2436 hyper = Html("img", src=img_url, alt=name) 2437 thumbnail += hyper 2438 2439 if usedescr: 2440 hyper += Html("p", name, inline=True) 2441 return thumbnail 2442 2443 def doc_link(self, handle, name, uplink=False, usedescr=True): 2444 """ 2445 create a hyperlink for the media object and returns it 2446 2447 @param: handle -- Document handle 2448 @param: name -- Document name 2449 @param: uplink -- If True, then "../../../" is inserted in front of 2450 the result. 2451 @param: usedescr -- Add description to hyperlink 2452 """ 2453 url = self.report.build_url_fname_html(handle, "img", uplink) 2454 name = html_escape(name) 2455 2456 # begin thumbnail division 2457 with Html("div", class_="thumbnail") as thumbnail: 2458 document_url = self.report.build_url_image("document.png", 2459 "images", uplink) 2460 2461 if not self.create_thumbs_only: 2462 document_link = Html("a", href=url, title=name) + ( 2463 Html("img", src=document_url, alt=name) 2464 ) 2465 else: 2466 document_link = Html("img", src=document_url, alt=name) 2467 2468 if usedescr: 2469 document_link += Html('br') + ( 2470 Html("span", name, inline=True) 2471 ) 2472 thumbnail += document_link 2473 return thumbnail 2474 2475 def place_link(self, handle, name, gid=None, uplink=False): 2476 """ 2477 Returns a hyperlink for place link 2478 2479 @param: handle -- repository handle from report database 2480 @param: name -- repository title 2481 @param: gid -- gramps id 2482 @param: uplink -- If True, then "../../../" is inserted in front of 2483 the result. 2484 """ 2485 url = self.report.build_url_fname_html(handle, "plc", uplink) 2486 2487 hyper = Html("a", html_escape(name), href=url, 2488 title=html_escape(name)) 2489 if not self.noid and gid: 2490 hyper += Html("span", " [%s]" % gid, class_="grampsid", inline=True) 2491 2492 # return hyperlink to its callers 2493 return hyper 2494 2495 def dump_place(self, place, table): 2496 """ 2497 Dump a place's information from within the database 2498 2499 @param: place -- Place object from the database 2500 @param: table -- Table from Placedetail 2501 """ 2502 if place in self.report.visited: 2503 return None 2504 self.report.visited.append(place) 2505 # add table body 2506 tbody = Html("tbody") 2507 table += tbody 2508 2509 gid = place.gramps_id 2510 if not self.noid and gid: 2511 trow = Html("tr") + ( 2512 Html("td", self._("Gramps ID"), class_="ColumnAttribute", 2513 inline=True), 2514 Html("td", gid, class_="ColumnValue", inline=True) 2515 ) 2516 tbody += trow 2517 2518 data = place.get_latitude() 2519 if data != "": 2520 trow = Html('tr') + ( 2521 Html("td", self._("Latitude"), class_="ColumnAttribute", 2522 inline=True), 2523 Html("td", data, class_="ColumnValue", inline=True) 2524 ) 2525 tbody += trow 2526 data = place.get_longitude() 2527 if data != "": 2528 trow = Html('tr') + ( 2529 Html("td", self._("Longitude"), class_="ColumnAttribute", 2530 inline=True), 2531 Html("td", data, class_="ColumnValue", inline=True) 2532 ) 2533 tbody += trow 2534 2535 mlocation = get_main_location(self.r_db, place) 2536 for (label, data) in [ 2537 (self._("Street"), mlocation.get(PlaceType.STREET, '')), 2538 (self._("Locality"), mlocation.get(PlaceType.LOCALITY, '')), 2539 (self._("City"), mlocation.get(PlaceType.CITY, '')), 2540 (self._("Church Parish"), 2541 mlocation.get(PlaceType.PARISH, '')), 2542 (self._("County"), mlocation.get(PlaceType.COUNTY, '')), 2543 (self._("State/ Province"), 2544 mlocation.get(PlaceType.STATE, '')), 2545 (self._("Postal Code"), place.get_code()), 2546 (self._("Province"), mlocation.get(PlaceType.PROVINCE, '')), 2547 (self._("Country"), mlocation.get(PlaceType.COUNTRY, ''))]: 2548 if data: 2549 trow = Html("tr") + ( 2550 Html("td", label, class_="ColumnAttribute", inline=True), 2551 Html("td", data, class_="ColumnValue", inline=True) 2552 ) 2553 tbody += trow 2554 2555 # display all related locations 2556 for placeref in place.get_placeref_list(): 2557 place_date = self.rlocale.get_date(placeref.get_date_object()) 2558 if place_date != "": 2559 parent_place = self.r_db.get_place_from_handle(placeref.ref) 2560 parent_name = parent_place.get_name().get_value() 2561 trow = Html('tr') + ( 2562 Html("td", self._("Locations"), class_="ColumnAttribute", 2563 inline=True), 2564 Html("td", parent_name, class_="ColumnValue", inline=True), 2565 Html("td", place_date, class_="ColumnValue", inline=True) 2566 ) 2567 tbody += trow 2568 2569 altloc = place.get_alternative_names() 2570 if altloc: 2571 tbody += Html("tr") + Html("td", " ", colspan=2) 2572 date_msg = self._("Date range in which the name is valid.") 2573 trow = Html("tr") + ( 2574 Html("th", self._("Alternate Names"), colspan=1, 2575 class_="ColumnAttribute", inline=True), 2576 Html("th", self._("Language"), colspan=1, 2577 class_="ColumnAttribute", inline=True), 2578 Html("th", date_msg, colspan=1, 2579 class_="ColumnAttribute", inline=True), 2580 ) 2581 tbody += trow 2582 for loc in altloc: 2583 place_date = self.rlocale.get_date(loc.date) 2584 trow = Html("tr") + ( 2585 Html("td", loc.get_value(), class_="ColumnValue", 2586 inline=True), 2587 Html("td", loc.get_language(), class_="ColumnValue", 2588 inline=True), 2589 Html("td", place_date, class_="ColumnValue", 2590 inline=True), 2591 ) 2592 tbody += trow 2593 2594 altloc = place.get_alternate_locations() 2595 if altloc: 2596 tbody += Html("tr") + Html("td", " ", colspan=2) 2597 trow = Html("tr") + ( 2598 Html("th", self._("Alternate Locations"), colspan=2, 2599 class_="ColumnAttribute", inline=True), 2600 ) 2601 tbody += trow 2602 for loc in (nonempt 2603 for nonempt in altloc if not nonempt.is_empty()): 2604 for (label, data) in [(self._("Street"), loc.street), 2605 (self._("Locality"), loc.locality), 2606 (self._("City"), loc.city), 2607 (self._("Church Parish"), loc.parish), 2608 (self._("County"), loc.county), 2609 (self._("State/ Province"), loc.state), 2610 (self._("Postal Code"), loc.postal), 2611 (self._("Country"), loc.country),]: 2612 if data: 2613 trow = Html("tr") + ( 2614 Html("td", label, class_="ColumnAttribute", 2615 inline=True), 2616 Html("td", data, class_="ColumnValue", inline=True) 2617 ) 2618 tbody += trow 2619 tbody += Html("tr") + Html("td", " ", colspan=2) 2620 2621 # encloses 2622 with Html("div", class_='subsection encloses') as encloses: 2623 tbody += encloses 2624 encloses += Html("h4", self._("Place Encloses"), inline=True) 2625 with Html("table", class_="infolist place") as table: 2626 encloses += table 2627 visited = [place.handle] 2628 for link in self.r_db.find_backlink_handles( 2629 place.handle, include_classes=['Place']): 2630 if link[1] in visited: 2631 continue 2632 visited.append(link[1]) 2633 c_place = self.r_db.get_place_from_handle(link[1]) 2634 placeref = None 2635 for placeref in c_place.get_placeref_list(): 2636 if placeref.ref == place.handle: 2637 gpfh = self.r_db.get_place_from_handle 2638 eplace = gpfh(placeref.ref) 2639 if not eplace: 2640 continue 2641 place_name = c_place.get_name().get_value() 2642 table += Html("tr") + Html("td", place_name) 2643 2644 # enclosed by 2645 with Html("div", class_='subsection encloses') as encloses: 2646 tbody += encloses 2647 encloses += Html("h4", self._("Enclosed By"), inline=True) 2648 with Html("table", class_="infolist place") as table: 2649 encloses += table 2650 visited = [place.handle] 2651 placeref = None 2652 for placeref in place.get_placeref_list(): 2653 if placeref.ref in visited: 2654 continue 2655 visited.append(placeref.ref) 2656 pplace = self.r_db.get_place_from_handle(placeref.ref) 2657 if not pplace: 2658 continue 2659 place_name = pplace.get_name().get_value() 2660 table += Html("tr") + Html("td", place_name) 2661 2662 # enclosed by 2663 tbody += Html("tr") + Html("td", " ") 2664 trow = Html("tr") + ( 2665 Html("th", self._("Enclosed By"), 2666 class_="ColumnAttribute", inline=True), 2667 ) 2668 tbody += trow 2669 for placeref in place.get_placeref_list(): 2670 parent_place = self.r_db.get_place_from_handle(placeref.ref) 2671 if parent_place: 2672 place_name = parent_place.get_name().get_value() 2673 if parent_place.handle in self.report.obj_dict[Place]: 2674 place_hyper = self.place_link(parent_place.handle, 2675 place_name, 2676 uplink=self.uplink) 2677 else: 2678 place_hyper = place_name 2679 trow = Html("tr") + ( 2680 Html("td", place_hyper, class_="ColumnValue", 2681 inline=True)) 2682 tbody += trow 2683 2684 # enclose 2685 tbody += Html("tr") + Html("td", " ") 2686 trow = Html("tr") + ( 2687 Html("th", self._("Place Encloses"), 2688 class_="ColumnAttribute", inline=True), 2689 ) 2690 tbody += trow 2691 for link in self.r_db.find_backlink_handles( 2692 place.handle, include_classes=['Place']): 2693 child_place = self.r_db.get_place_from_handle(link[1]) 2694 placeref = None 2695 for placeref in child_place.get_placeref_list(): 2696 if placeref.ref == place.handle: 2697 place_name = child_place.get_name().get_value() 2698 if child_place.handle in self.report.obj_dict[Place]: 2699 place_hyper = self.place_link(child_place.handle, 2700 place_name, 2701 uplink=self.uplink) 2702 else: 2703 place_hyper = place_name 2704 trow = Html("tr") + ( 2705 Html("td", place_hyper, 2706 class_="ColumnValue", inline=True)) 2707 tbody += trow 2708 2709 # return place table to its callers 2710 return table 2711 2712 def repository_link(self, repository_handle, name, 2713 gid=None, uplink=False): 2714 """ 2715 Returns a hyperlink for repository links 2716 2717 @param: repository_handle -- repository handle from report database 2718 @param: name -- repository title 2719 @param: gid -- gramps id 2720 @param: uplink -- If True, then "../../../" is inserted in 2721 front of the result. 2722 """ 2723 url = self.report.build_url_fname_html(repository_handle, 2724 'repo', uplink) 2725 name = html_escape(name) 2726 2727 hyper = Html("a", name, href=url, title=name) 2728 2729 if not self.noid and gid: 2730 hyper += Html("span", '[%s]' % gid, class_="grampsid", inline=True) 2731 return hyper 2732 2733 def dump_repository_ref_list(self, repo_ref_list): 2734 """ 2735 Dumps the repository 2736 2737 @param: repo_ref_list -- The list of repositories references 2738 """ 2739 if not repo_ref_list: 2740 return None 2741 # Repository list division... 2742 with Html("div", class_="subsection", 2743 id="repositories") as repositories: 2744 repositories += Html("h4", self._("Repositories"), inline=True) 2745 2746 with Html("table", class_="infolist") as table: 2747 repositories += table 2748 2749 thead = Html("thead") 2750 table += thead 2751 2752 trow = Html("tr") + ( 2753 Html("th", self._("Number"), class_="ColumnRowLabel", 2754 inline=True), 2755 Html("th", self._("Title"), class_="ColumnName", 2756 inline=True), 2757 Html("th", self._("Type"), class_="ColumnName", 2758 inline=True), 2759 Html("th", self._("Call number"), class_="ColumnName", 2760 inline=True) 2761 ) 2762 thead += trow 2763 2764 tbody = Html("tbody") 2765 table += tbody 2766 2767 index = 1 2768 for repo_ref in repo_ref_list: 2769 repo = self.r_db.get_repository_from_handle(repo_ref.ref) 2770 if repo: 2771 trow = Html("tr") + ( 2772 Html("td", index, class_="ColumnRowLabel", 2773 inline=True), 2774 Html("td", 2775 self.repository_link(repo_ref.ref, 2776 repo.get_name(), 2777 repo.get_gramps_id(), 2778 self.uplink)), 2779 Html("td", 2780 self._(repo_ref.get_media_type().xml_str()), 2781 class_="ColumnName"), 2782 Html("td", repo_ref.get_call_number(), 2783 class_="ColumnName") 2784 ) 2785 tbody += trow 2786 index += 1 2787 return repositories 2788 2789 def dump_residence(self, has_res): 2790 """ 2791 Creates a residence from the database 2792 2793 @param: has_res -- The residence to use 2794 """ 2795 if not has_res: 2796 return None 2797 2798 # begin residence division 2799 with Html("div", class_="content Residence") as residence: 2800 residence += Html("h4", self._("Residence"), inline=True) 2801 2802 with Html("table", class_="infolist place") as table: 2803 residence += table 2804 2805 place_handle = has_res.get_place_handle() 2806 if place_handle: 2807 place = self.r_db.get_place_from_handle(place_handle) 2808 if place: 2809 self.dump_place(place, table) 2810 2811 descr = has_res.get_description() 2812 if descr: 2813 2814 trow = Html("tr") 2815 if len(table) == 3: 2816 # append description row to tbody element 2817 # of dump_place 2818 table[-2] += trow 2819 else: 2820 # append description row to table element 2821 table += trow 2822 2823 trow.extend(Html("td", self._("Description"), 2824 class_="ColumnAttribute", inline=True)) 2825 trow.extend(Html("td", descr, class_="ColumnValue", 2826 inline=True)) 2827 2828 # return information to its callers 2829 return residence 2830 2831 def display_bkref(self, bkref_list, depth): 2832 """ 2833 Display a reference list for an object class 2834 2835 @param: bkref_list -- The reference list 2836 @param: depth -- The style of list to use 2837 """ 2838 list_style = "1", "a", "I", "A", "i" 2839 ordered = Html("ol", class_="Col1", role="Volume-n-Page") 2840 ordered.attr += " type=%s" % list_style[depth] 2841 if depth > len(list_style): 2842 return "" 2843 # Sort by the role of the object at the bkref_class, bkref_handle 2844 def sort_by_role(obj): 2845 """ 2846 Sort by role 2847 """ 2848 if obj[2] == "Primary": 2849 role = "0" 2850 elif obj[2] == "Family": 2851 role = "1" 2852 else: 2853 if self.reference_sort: 2854 role = obj[2] # name 2855 elif len(obj[2].split('-')) > 1: 2856 dummy_cal, role = obj[2].split(':') # date in ISO format 2857 # dummy_cal is the original calendar. remove it. 2858 if len(role.split(' ')) == 2: 2859 # for sort, remove the modifier before, after... 2860 (dummy_modifier, role) = role.split(' ') 2861 else: 2862 role = "3" 2863 return role 2864 2865 for (bkref_class, bkref_handle, role) in sorted( 2866 bkref_list, key=lambda x: 2867 sort_by_role(x)): 2868 list_html = Html("li") 2869 path = self.report.obj_dict[bkref_class][bkref_handle][0] 2870 name = self.report.obj_dict[bkref_class][bkref_handle][1] 2871 gid = self.report.obj_dict[bkref_class][bkref_handle][2] 2872 if role != "": 2873 if self.reference_sort: 2874 role = "" 2875 elif role[1:2] == ':': 2876 # cal is the original calendar 2877 cal, role = role.split(':') 2878 # conver ISO date to Date for translation. 2879 # all modifiers are in english, so convert them 2880 # to the local language 2881 if len(role.split(' - ')) > 1: 2882 (date1, date2) = role.split(' - ') 2883 role = self._("between") + " " + date1 + " " 2884 role += self._("and") + " " + date2 2885 elif len(role.split(' ')) == 2: 2886 (pref, date) = role.split(' ') 2887 if "aft" in pref: 2888 role = self._("after") + " " + date 2889 if "bef" in pref: 2890 role = self._("before") + " " + date 2891 if pref in ("abt", "about"): 2892 role = self._("about") + " " + date 2893 if "c" in pref: 2894 role = self._("circa") + " " + date 2895 if "around" in pref: 2896 role = self._("around") + " " + date 2897 # parse is done in the default language 2898 date = _dp.parse(role) 2899 # reset the date to the original calendar 2900 cdate = date.to_calendar(Date.calendar_names[int(cal)]) 2901 ldate = self.rlocale.get_date(cdate) 2902 role = " (%s) " % ldate 2903 else: 2904 role = " (%s) " % self._(role) 2905 ordered += list_html 2906 if path == "": 2907 list_html += name 2908 list_html += self.display_bkref( 2909 self.report.bkref_dict[bkref_class][bkref_handle], 2910 depth+1) 2911 else: 2912 url = self.report.build_url_fname(path, uplink=self.uplink) 2913 if not self.noid and gid != "": 2914 gid_html = Html("span", " [%s]" % gid, 2915 class_="grampsid", inline=True) 2916 else: 2917 gid_html = "" 2918 list_html += Html("a", href=url) + name + role + gid_html 2919 return ordered 2920 2921 def display_bkref_list(self, obj_class, obj_handle): 2922 """ 2923 Display a reference list for an object class 2924 2925 @param: obj_class -- The object class to use 2926 @param: obj_handle -- The handle to use 2927 """ 2928 bkref_list = self.report.bkref_dict[obj_class][obj_handle] 2929 if not bkref_list: 2930 return None 2931 # begin references division and title 2932 with Html("div", class_="subsection", id="references") as section: 2933 section += Html("h4", self._("References"), inline=True) 2934 depth = 0 2935 ordered = self.display_bkref(bkref_list, depth) 2936 section += ordered 2937 return section 2938 2939 # ----------------------------------------------------------------------- 2940 # # Web Page Fortmatter and writer 2941 # ----------------------------------------------------------------------- 2942 def xhtml_writer(self, htmlinstance, output_file, sio, date): 2943 """ 2944 Will format, write, and close the file 2945 2946 @param: output_file -- Open file that is being written to 2947 @param: htmlinstance -- Web page created with libhtml 2948 src/plugins/lib/libhtml.py 2949 """ 2950 htmlinstance.write(partial(print, file=output_file)) 2951 2952 # closes the file 2953 self.report.close_file(output_file, sio, date) 2954 2955