diff --git a/src/plugins/NarrativeWeb.py b/src/plugins/NarrativeWeb.py index 659a5edfc..400267d44 100644 --- a/src/plugins/NarrativeWeb.py +++ b/src/plugins/NarrativeWeb.py @@ -42,6 +42,7 @@ Narrative Web Page generator. # #------------------------------------------------------------------------ import os +import re import md5 import time import locale @@ -190,19 +191,11 @@ wrapper = TextWrapper() wrapper.break_log_words = True wrapper.width = 20 -# This list of characters defines which hexadecimal entity certain -# 'special characters' with be transformed into for valid HTML -# rendering. The variety of quotes with spaces are to assist in -# appropriately typesetting curly quotes and apostrophes. -html_escape_table = { + +_html_dbl_quotes = re.compile(r'([^"]*) " ([^"]*) " (.*)', re.VERBOSE) +_html_sng_quotes = re.compile(r"([^']*) ' ([^']*) ' (.*)", re.VERBOSE) +_html_replacement = { "&" : "&", - ' "' : " “", - '" ' : "” ", - " '" : " ‘", - "' " : "’ ", - "'s " : "’s ", - '"' : """, - "'" : "'", ">" : ">", "<" : "<", } @@ -211,7 +204,30 @@ html_escape_table = { # special characters for presentation in HTML based on the above list. def html_escape(text): """Convert the text and replace some characters with a &# variant.""" - return ''.join([html_escape_table.get(c, c) for c in text]) + + # First single characters, no quotes + text = ''.join([_html_replacement.get(c, c) for c in text]) + + # Deal with double quotes. + while 1: + m = _html_dbl_quotes.match(text) + if not m: + break + text = m.group(1) + '“' + m.group(2) + '”' + m.group(3) + # Replace remaining double quotes. + text = text.replace('"', '"') + + # Deal with single quotes. + text = text.replace("'s ", '’s ') + while 1: + m = _html_sng_quotes.match(text) + if not m: + break + text = m.group(1) + '‘' + m.group(2) + '’' + m.group(3) + # Replace remaining single quotes. + text = text.replace("'", ''') + + return text def name_to_md5(text): @@ -580,6 +596,7 @@ class BasePage: source = db.get_source_from_handle(shandle) title = source.get_title() of.write('\t\t\t
  • is done in source_link() self.source_link(of, source.handle, title, source.gramps_id, True) of.write('\n') @@ -989,7 +1006,7 @@ class PlaceListPage(BasePage): place = db.get_place_from_handle(handle) n = ReportUtils.place_name(db, handle) - if not n or len(n) == 0: + if not n: continue letter = normalize('NFD', n)[0].upper() @@ -1505,7 +1522,7 @@ class SourcePage(BasePage): def __init__(self, report, title, handle, src_list): db = report.database - source = db.get_source_from_handle( handle) + source = db.get_source_from_handle(handle) BasePage.__init__(self, report, title, source.gramps_id) of = self.report.create_file(source.get_handle(), 'src') @@ -1547,11 +1564,9 @@ class SourcePage(BasePage): class GalleryPage(BasePage): - def __init__(self, report, title, handle_set): + def __init__(self, report, title): BasePage.__init__(self, report, title) - # TODO. What to do with handle_set? - db = report.database of = self.report.create_file("gallery") self.display_header(of, _('Gallery'), content_divid='Gallery') @@ -1966,31 +1981,100 @@ class IndividualPage(BasePage): if not evt_ref_list: return + db = self.report.database + of.write('\t
    \n') of.write('\t\t

    %s

    \n' % _('Events')) of.write('\t\t\n') - db = self.report.database + # table head + of.write('\t\t\t\n') + for h in (_('event|Type'), _('Date'), _('Place'), _('Description'), _('Notes')): + of.write('\t\t\t\t' % h) + of.write('\t\t\t\n') + of.write('\t\t\t\n') + for event_ref in evt_ref_list: event = db.get_event_from_handle(event_ref.ref) if event: - evt_name = str(event.get_type()) + self.display_event_row(of, event, event_ref) - if event_ref.get_role() == EventRoleType.PRIMARY: - of.write('\t\t\t\n') - of.write('\t\t\t\t\n' % evt_name) - else: - of.write('\t\t\t\n') - of.write('\t\t\t\t\n' \ - % (evt_name, event_ref.get_role())) + of.write('\t\t\t\n') + of.write('\t\t\t\n') - of.write('\t\t\t\t\n') - of.write('\t\t\t\n') of.write('\t\t
    %s
    %s
    %s (%s)
    ') - of.write(self.format_event(event, event_ref)) - of.write('
    \n') of.write('\t
    \n\n') + def display_event_row(self, of, event, event_ref): + evt_name = str(event.get_type()) + + of.write('\t\t\t\t\n') + + # Type + if event_ref.get_role() == EventRoleType.PRIMARY: + txt = u"%(evt_name)s" % locals() + else: + event_role = event_ref.get_role() + txt = u"%(evt_name)s (%(evt_role)s)" % locals() + txt = txt or ' ' + of.write('\t\t\t\t\t%s\n' % txt) + + # Date + txt = _dd.display(event.get_date_object()) + txt = txt or ' ' + of.write('\t\t\t\t\t%s\n' % txt) + + # Place + place_handle = event.get_place_handle() + if place_handle: + # TODO. Figure out what this is for. + #if self.place_list.has_key(place_handle): + # if lnk not in self.place_list[place_handle]: + # self.place_list[place_handle].append(lnk) + #else: + # self.place_list[place_handle] = [lnk] + + place = self.place_link_str(place_handle, + ReportUtils.place_name(self.report.database, place_handle), + up=True) + else: + place = None + txt = place or ' ' + of.write('\t\t\t\t\t%s\n' % txt) + + # Description + txt = event.get_description() + txt = txt or ' ' + of.write('\t\t\t\t\t%s\n' % txt) + + # Attributes + # TODO. See format_event + + # Notes. Deal with list of notes. + of.write('\t\t\t\t\t\n') + done_first_note = False + notelist = event.get_note_list() + notelist.extend(event_ref.get_note_list()) + for notehandle in notelist: + note = db.get_note_from_handle(notehandle) + if note: + note_text = note.get() + if note_text: + if note.get_format(): + txt = u"
    %s
    " % note_text + else: + # TODO. Decide what to do with multiline notes. + txt = u" ".join(note_text.split("\n")) + if not done_first_note: + of.write('\t\t\t\t\t\t
      \n') + txt = txt or ' ' + of.write('\t\t\t\t\t\t\t
    1. %s
    2. \n' % txt) + if done_first_note: + of.write('\t\t\t\t\t\t
    \n') + of.write('\t\t\t\t\t\n') + + of.write('\t\t\t\t\n') + def display_addresses(self, of): alist = self.person.get_address_list() @@ -2283,10 +2367,12 @@ class IndividualPage(BasePage): of.write('
  • ') self.pedigree_person(of, child) of.write('
  • \n') - of.write('\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\n') + of.write('\t\t\t\t\t\t\t\t\t\t\n') + of.write('\t\t\t\t\t\t\t\t\t\n') else: of.write('\n') + # TODO. This function must be converted similar to display_ind_events and display_event_row def format_event(self, event, event_ref): db = self.report.database lnk = (self.report.cur_fname, self.page_title, self.gid) @@ -2308,9 +2394,9 @@ class IndividualPage(BasePage): date = _dd.display(event.get_date_object()) if date and place: - text = _("%(date) s   at    %(place)s") % { 'date': date, 'place': place } + text = _("%(date)s   at   %(place)s") % { 'date': date, 'place': place } elif place: - text = _("at    %(place)s") % { 'place': place } + text = _("at   %(place)s") % { 'place': place } elif date: text = date else: @@ -2613,7 +2699,7 @@ class NavWebReport(Report): SourcesPage(self, self.title, source_list.keys()) - for key in list(source_list): + for key in source_list: SourcePage(self, self.title, key, source_list) self.progress.step() @@ -2633,7 +2719,7 @@ class NavWebReport(Report): self.progress.set_pass(_("Creating media pages"), len(self.photo_list)) - GalleryPage(self, self.title, source_list) + GalleryPage(self, self.title) prev = None total = len(self.photo_list)