NAVWEB and WEBCAL: some minor corrections (#980)

* NAVWEB: set unused media to False by default

Fixes #11496

* Navweb: Center correctly the map in the web page

* Webcal: Dropmenu doesn't work if only one year.

* Navweb: Add notes to updates and delete empty rows

* Navweb: some code cleanup.

* Navweb: remove unused variable

* Narweb: references enhancement on place pages.

* Navweb: convert the years in gregorian cal.

* Narweb: remove unused argument

* Narweb: really solves the pyICU problem

* WEBCAL: missing death symbol
This commit is contained in:
Serge Noiraud 2020-01-17 11:46:40 +01:00 committed by GitHub
parent a2ae7b93fc
commit 763f2738dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 42 deletions

View File

@ -31,7 +31,7 @@ body#FamilyMap {
margin-left: 10px; margin-left: 10px;
margin-right: 10px; margin-right: 10px;
border: solid 4px #000; border: solid 4px #000;
margin: 0px auto; margin: 20px auto;
width: 800px; width: 800px;
height: 400px; height: 400px;
max-width: 90%; max-width: 90%;

View File

@ -2984,7 +2984,7 @@ class BasePage: # pylint: disable=C1001
gid = self.report.obj_dict[bkref_class][bkref_handle][2] gid = self.report.obj_dict[bkref_class][bkref_handle][2]
if role != "": if role != "":
if self.reference_sort: if self.reference_sort:
role = "" role = self.birth_death_dates(gid)
elif role[1:2] == ':': elif role[1:2] == ':':
# cal is the original calendar # cal is the original calendar
cal, role = role.split(':') cal, role = role.split(':')
@ -3012,7 +3012,10 @@ class BasePage: # pylint: disable=C1001
# reset the date to the original calendar # reset the date to the original calendar
cdate = date.to_calendar(Date.calendar_names[int(cal)]) cdate = date.to_calendar(Date.calendar_names[int(cal)])
ldate = self.rlocale.get_date(cdate) ldate = self.rlocale.get_date(cdate)
role = " (%s) " % ldate evtype = self.event_for_date(gid, cdate)
if evtype:
evtype = " " + evtype
role = " (%s) " % (ldate + evtype)
else: else:
role = " (%s) " % self._(role) role = " (%s) " % self._(role)
ordered += list_html ordered += list_html
@ -3031,6 +3034,45 @@ class BasePage: # pylint: disable=C1001
list_html += Html("a", href=url) + name + role + gid_html list_html += Html("a", href=url) + name + role + gid_html
return ordered return ordered
def event_for_date(self, gid, date):
"""
return the event type
"""
pers = self.r_db.get_person_from_gramps_id(gid)
if pers:
evt_ref_list = pers.get_event_ref_list()
if evt_ref_list:
for evt_ref in evt_ref_list:
evt = self.r_db.get_event_from_handle(evt_ref.ref)
if evt:
evdate = evt.get_date_object()
# convert date to gregorian
_date = str(evdate.to_calendar("gregorian"))
if _date == str(date):
return self._(str(evt.get_type()))
return ""
def birth_death_dates(self, gid):
"""
return the birth and death date for the person
"""
pers = self.r_db.get_person_from_gramps_id(gid)
if pers:
birth = death = ""
evt_birth = get_birth_or_fallback(self.r_db, pers)
if evt_birth:
birthd = evt_birth.get_date_object()
# convert date to gregorian to avoid strange years
birth = str(birthd.to_calendar("gregorian").get_year())
evt_death = get_death_or_fallback(self.r_db, pers)
if evt_death:
deathd = evt_death.get_date_object()
# convert date to gregorian to avoid strange years
death = str(deathd.to_calendar("gregorian").get_year())
return "(%s-%s)" % (birth, death)
else:
return ""
def display_bkref_list(self, obj_class, obj_handle): def display_bkref_list(self, obj_class, obj_handle):
""" """
Display a reference list for an object class Display a reference list for an object class

View File

@ -31,6 +31,7 @@ from unicodedata import normalize
from collections import defaultdict from collections import defaultdict
from hashlib import md5 from hashlib import md5
import re import re
import locale # Used only with pyICU
import logging import logging
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
@ -439,7 +440,10 @@ def sort_places(dbase, handle_list, rlocale=glocale):
for name in temp_list: for name in temp_list:
if isinstance(name, bytes): if isinstance(name, bytes):
name = name.decode('utf-8') name = name.decode('utf-8')
sorted_lists.append((name, pname_sub[name][0])) slist = sorted(((sortnames[x], x) for x in pname_sub[name]),
key=lambda x: rlocale.sort_key(x[0]))
for entry in slist:
sorted_lists.append(entry)
return sorted_lists return sorted_lists
@ -622,23 +626,42 @@ def first_letter(string, rlocale=glocale):
# no special case # no special case
return norm_unicode[0].upper() return norm_unicode[0].upper()
def primary_difference(prev_key, new_key, rlocale=glocale):
"""
The PyICU collation doesn't work if you want to sort in another language
So we use this method to do the work correctly.
Returns true if there is a primary difference between the two parameters try:
See http://www.gramps-project.org/bugs/view.php?id=2933#c9317 if import PyICU # pylint : disable=wrong-import-position
letter[i]+'a' < letter[i+1]+'b' and letter[i+1]+'a' < letter[i]+'b' is PRIM_COLL = PyICU.Collator.createInstance(PyICU.Locale(COLLATE_LANG))
true then the letters should be grouped together PRIM_COLL.setStrength(PRIM_COLL.PRIMARY)
The test characters here must not be any that are used in contractions. def primary_difference(prev_key, new_key, rlocale=glocale):
""" """
Try to use the PyICU collation.
If we generate a report for another language, make sure we use the good
collation sequence
"""
collation = PRIM_COLL
if rlocale.lang != locale.getlocale(locale.LC_COLLATE)[0]:
encoding = rlocale.encoding if rlocale.encoding else "UTF-8"
collate_lang = PyICU.Locale(rlocale.collation+"."+encoding)
collation = PyICU.Collator.createInstance(collate_lang)
return collation.compare(prev_key, new_key) != 0
return rlocale.sort_key(prev_key + "e") >= \ except:
rlocale.sort_key(new_key + "f") or \ def primary_difference(prev_key, new_key, rlocale=glocale):
rlocale.sort_key(new_key + "e") >= \ """
rlocale.sort_key(prev_key + "f") The PyICU collation is not available.
Returns true if there is a primary difference between the two parameters
See http://www.gramps-project.org/bugs/view.php?id=2933#c9317 if
letter[i]+'a' < letter[i+1]+'b' and letter[i+1]+'a' < letter[i]+'b' is
true then the letters should be grouped together
The test characters here must not be any that are used in contractions.
"""
return rlocale.sort_key(prev_key + "e") >= \
rlocale.sort_key(new_key + "f") or \
rlocale.sort_key(new_key + "e") >= \
rlocale.sort_key(prev_key + "f")
def get_first_letters(dbase, handle_list, key, rlocale=glocale): def get_first_letters(dbase, handle_list, key, rlocale=glocale):
""" """

View File

@ -1948,7 +1948,7 @@ class NavWebOptions(MenuReportOptions):
self.__gallery_changed) self.__gallery_changed)
self.__unused = BooleanOption( self.__unused = BooleanOption(
_("Include unused images and media objects"), True) _("Include unused images and media objects"), False)
self.__unused.set_help(_('Whether to include unused or unreferenced' self.__unused.set_help(_('Whether to include unused or unreferenced'
' media objects')) ' media objects'))
addopt("unused", self.__unused) addopt("unused", self.__unused)

View File

@ -45,9 +45,9 @@ from gramps.plugins.lib.libhtml import Html
#------------------------------------------------ #------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage from gramps.plugins.webreport.basepage import BasePage
from gramps.gen.display.place import displayer as _pd from gramps.gen.display.place import displayer as _pd
from gramps.plugins.webreport.common import (FULLCLEAR, _EVENTMAP) from gramps.plugins.webreport.common import (FULLCLEAR, _EVENTMAP, html_escape)
from gramps.gen.lib import (Person, Family, Event, Place, Source, Repository, from gramps.gen.lib import (Person, Family, Event, Place, Source, Repository,
Media) Media, Note, Citation)
from gramps.gen.lib.date import Date from gramps.gen.lib.date import Date
_ = glocale.translation.sgettext _ = glocale.translation.sgettext
@ -66,6 +66,12 @@ class UpdatesPage(BasePage):
""" """
BasePage.__init__(self, report, title) BasePage.__init__(self, report, title)
ldatec = 0 ldatec = 0
self.inc_repository = self.report.options['inc_repository']
self.inc_families = self.report.options['inc_families']
self.inc_events = self.report.options['inc_events']
self.inc_places = self.report.options['inc_places']
self.inc_sources = self.report.options['inc_sources']
self.inc_gallery = False
output_file, sio = self.report.create_file("updates") output_file, sio = self.report.create_file("updates")
result = self.write_header(self._('New and updated objects')) result = self.write_header(self._('New and updated objects'))
@ -93,35 +99,35 @@ class UpdatesPage(BasePage):
if people is not None: if people is not None:
section += people section += people
if self.report.options['inc_families']: if self.inc_families:
header = self._("Families") header = self._("Families")
section += Html("h4", header) section += Html("h4", header)
families = self.list_people_changed(Family) families = self.list_people_changed(Family)
if families is not None: if families is not None:
section += families section += families
if self.report.options['inc_events']: if self.inc_events:
header = self._("Events") header = self._("Events")
section += Html("h4", header) section += Html("h4", header)
events = self.list_people_changed(Event) events = self.list_people_changed(Event)
if events is not None: if events is not None:
section += events section += events
if self.report.options['inc_places']: if self.inc_places:
header = self._("Places") header = self._("Places")
section += Html("h4", header) section += Html("h4", header)
places = self.list_people_changed(Place) places = self.list_people_changed(Place)
if places is not None: if places is not None:
section += places section += places
if self.report.options['inc_sources']: if self.inc_sources:
header = self._("Sources") header = self._("Sources")
section += Html("h4", header) section += Html("h4", header)
sources = self.list_people_changed(Source) sources = self.list_people_changed(Source)
if sources is not None: if sources is not None:
section += sources section += sources
if self.report.options['inc_repository']: if self.inc_repository:
header = self._("Repositories") header = self._("Repositories")
section += Html("h4", header) section += Html("h4", header)
repos = self.list_people_changed(Repository) repos = self.list_people_changed(Repository)
@ -130,12 +136,19 @@ class UpdatesPage(BasePage):
if (self.report.options['gallery'] and not if (self.report.options['gallery'] and not
self.report.options['create_thumbs_only']): self.report.options['create_thumbs_only']):
self.inc_gallery = True
header = self._("Media") header = self._("Media")
section += Html("h4", header) section += Html("h4", header)
media = self.list_people_changed(Media) media = self.list_people_changed(Media)
if media is not None: if media is not None:
section += media section += media
header = self._("Notes")
section += Html("h4", header)
events = self.list_notes()
if events is not None:
section += events
# create clear line for proper styling # create clear line for proper styling
# create footer section # create footer section
footer = self.write_footer(ldatec) footer = self.write_footer(ldatec)
@ -145,6 +158,122 @@ class UpdatesPage(BasePage):
# and close the file # and close the file
self.xhtml_writer(homepage, output_file, sio, ldatec) self.xhtml_writer(homepage, output_file, sio, ldatec)
def list_notes(self):
"""
List all notes with last change date
"""
nb_items = 0
section = ""
def sort_on_change(handle):
""" sort records based on the last change time """
fct = self.report.database.get_note_from_handle
obj = fct(handle)
timestamp = obj.get_change_time()
return timestamp
note_list = self.report.database.get_note_handles()
obj_list = sorted(note_list, key=sort_on_change, reverse=True)
with Html("table", class_="list", id="list") as section:
for handle in obj_list:
show = False
date = obj = None
obj = self.report.database.get_note_from_handle(handle)
if obj:
text = html_escape(obj.get()[:50])
timestamp = obj.get_change_time()
if timestamp - self.maxdays > 0:
handle_list = set(
self.report.database.find_backlink_handles(
handle,
include_classes=['Person', 'Family', 'Event',
'Place', 'Media', 'Source',
'Citation', 'Repository',
]))
tims = localtime(timestamp)
odat = Date(tims.tm_year, tims.tm_mon, tims.tm_mday)
date = self.rlocale.date_displayer.display(odat)
date += strftime(' %X', tims)
if handle_list:
srbd = self.report.database
srbkref = self.report.bkref_dict
for obj_t, r_handle in handle_list:
if obj_t == 'Person':
if r_handle in srbkref[Person]:
name = self.new_person_link(r_handle)
show = True
elif obj_t == 'Family':
if r_handle in srbkref[Family]:
fam = srbd.get_family_from_handle(
r_handle)
fam = self._("Family")
name = self.family_link(r_handle, fam)
if self.inc_families:
show = True
elif obj_t == 'Place':
if r_handle in srbkref[Place]:
plc = srbd.get_place_from_handle(
r_handle)
plcn = _pd.display(self.report.database,
plc)
name = self.place_link(r_handle, plcn)
if self.inc_places:
show = True
elif obj_t == 'Event':
if r_handle in srbkref[Event]:
evt = srbd.get_event_from_handle(
r_handle)
evtn = self._(evt.get_type().xml_str())
name = self.event_link(r_handle, evtn)
if self.inc_events:
show = True
elif obj_t == 'Media':
if r_handle in srbkref[Media]:
media = srbd.get_media_from_handle(
r_handle)
evtn = media.get_description()
name = self.media_link(r_handle, evtn,
evtn,
usedescr=False)
if self.inc_gallery:
show = True
elif obj_t == 'Citation':
if r_handle in srbkref[Citation]:
cit = srbd.get_event_from_handle(
r_handle)
citsrc = cit.source_handle
evtn = self._("Citation")
name = self.source_link(citsrc, evtn)
if self.inc_sources:
show = True
elif obj_t == 'Source':
if r_handle in srbkref[Source]:
src = srbd.get_source_from_handle(
r_handle)
evtn = src.get_title()
name = self.source_link(r_handle, evtn)
if self.inc_sources:
show = True
elif obj_t == 'Repository':
if r_handle in srbkref[Repository]:
rep = srbd.get_repository_from_handle(
r_handle)
evtn = rep.get_name()
name = self.repository_link(r_handle,
evtn)
if self.inc_repository:
show = True
if show:
row = Html("tr")
section += row
row += Html("td", date, class_="date")
row += Html("td", text)
row += Html("td", name)
nb_items += 1
if nb_items > self.nbr:
break
return section
def list_people_changed(self, object_type): def list_people_changed(self, object_type):
""" """
List all records with last change date List all records with last change date
@ -180,8 +309,6 @@ class UpdatesPage(BasePage):
key=sort_on_change, reverse=True) key=sort_on_change, reverse=True)
with Html("table", class_="list", id="list") as section: with Html("table", class_="list", id="list") as section:
for handle in obj_list: for handle in obj_list:
row = Html("tr")
section += row
date = obj = None date = obj = None
name = "" name = ""
obj = fct(handle) obj = fct(handle)
@ -236,6 +363,8 @@ class UpdatesPage(BasePage):
odat = Date(tims.tm_year, tims.tm_mon, tims.tm_mday) odat = Date(tims.tm_year, tims.tm_mon, tims.tm_mday)
date = self.rlocale.date_displayer.display(odat) date = self.rlocale.date_displayer.display(odat)
date += strftime(' %X', tims) date += strftime(' %X', tims)
row = Html("tr")
section += row
row += Html("td", date, class_="date") row += Html("td", date, class_="date")
row += Html("td", name) row += Html("td", name)
return section return section

View File

@ -63,6 +63,7 @@ from gramps.gen.plug.menu import (BooleanOption, NumberOption, StringOption,
from gramps.gen.utils.config import get_researcher from gramps.gen.utils.config import get_researcher
from gramps.gen.utils.alive import probably_alive from gramps.gen.utils.alive import probably_alive
from gramps.gen.utils.db import get_death_or_fallback from gramps.gen.utils.db import get_death_or_fallback
from gramps.gen.utils.symbols import Symbols
from gramps.gen.datehandler import displayer as _dd from gramps.gen.datehandler import displayer as _dd
from gramps.gen.display.name import displayer as _nd from gramps.gen.display.name import displayer as _nd
@ -464,20 +465,14 @@ class WebCalReport(Report):
"if (x.className === \"nav\") { x.className += \"" "if (x.className === \"nav\") { x.className += \""
" responsive\"; } else { x.className = \"nav\"; }" " responsive\"; } else { x.className = \"nav\"; }"
" }</script>") " }</script>")
if self.multiyear: head += menuscript
head += menuscript
# begin header section # begin header section
if self.multiyear: headerdiv = Html("div", id='header') + (
headerdiv = Html("div", id='header') + ( Html("<button href=\"javascript:void(0);\" class=\"navIcon\""
Html("<a href=\"javascript:void(0);\" class=\"navIcon\"" " onclick=\"navFunction()\">&#8801;</button>")) + (
" onclick=\"navFunction()\">&#8801;</a>")) + ( Html("h1", self.title_text,
Html("h1", html_escape(title), id="SiteTitle", inline=True))
id="SiteTitle", inline=True))
else:
headerdiv = Html("div", id='header') + (
Html("h1", html_escape(title),
id="SiteTitle", inline=True))
body += headerdiv body += headerdiv
# add body id tag if not None # add body id tag if not None
@ -2168,12 +2163,14 @@ def get_day_list(event_date, holiday_list, bday_anniv_list, rlocale=glocale):
#age_str.format(precision=1, as_age=False, dlocale=rlocale) #age_str.format(precision=1, as_age=False, dlocale=rlocale)
age_str = age_str.format(precision=1, as_age=False, dlocale=rlocale) age_str = age_str.format(precision=1, as_age=False, dlocale=rlocale)
symbols = Symbols()
death_idx = symbols.DEATH_SYMBOL_SHADOWED_LATIN_CROSS
death_symbol = symbols.get_death_symbol_for_char(death_idx)
# a birthday # a birthday
if event == 'Birthday': if event == 'Birthday':
if age_at_death is not None: if age_at_death is not None:
death_symbol = "&#10014;" # latin cross for html code
trans_date = trans_text("Died %(death_date)s.") trans_date = trans_text("Died %(death_date)s.")
translated_date = rlocale.get_date(dead_event_date) translated_date = rlocale.get_date(dead_event_date)
mess = trans_date % {'death_date' : translated_date} mess = trans_date % {'death_date' : translated_date}
@ -2194,7 +2191,7 @@ def get_day_list(event_date, holiday_list, bday_anniv_list, rlocale=glocale):
# a death # a death
if event == 'Death': if event == 'Death':
txt_str = (text + ', <em>' txt_str = (text + ', ' + death_symbol + ' <em>'
+ (_('%s since death') % str(age_str) if nyears + (_('%s since death') % str(age_str) if nyears
else _('death')) else _('death'))
+ '</em>') + '</em>')