Merge pull request #908 from SNoiraud:FR11336

New narrative web and web calendar features:

* Allow urls in the user's css files
* Allow alternate stylesheets in pages for narrative web and webcal
* Webcal: incorrect results when divorce event.
* Some pylint improvements

Resolves #11336.
This commit is contained in:
Nick Hall 2019-10-05 18:07:54 +01:00
commit f5861169fe
4 changed files with 156 additions and 56 deletions

View File

@ -752,7 +752,6 @@ class BasePage: # pylint: disable=C1001
if latitude and longitude: if latitude and longitude:
latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8")
if latitude is not None: if latitude is not None:
etype = event.get_type()
place_lat_long.append([latitude, longitude, placetitle, place_lat_long.append([latitude, longitude, placetitle,
place_handle, event]) place_handle, event])
@ -1422,8 +1421,23 @@ class BasePage: # pylint: disable=C1001
Html("link", type="text/css", href=url3, Html("link", type="text/css", href=url3,
media='print', rel="stylesheet", indent=False), media='print', rel="stylesheet", indent=False),
Html("link", type="text/css", href=url2, Html("link", type="text/css", href=url2,
media="screen", rel="stylesheet", indent=False), media="screen", title=self._("Default"),
rel="stylesheet", indent=False),
) )
# create all alternate stylesheets
# Cannot use it on local files (file://)
for css_f in CSS:
already_done = False
for css_fn in ("UsEr_", "Basic", "Mainz", "Nebraska"):
if css_fn in css_f and not already_done:
css_f = css_f.replace("UsEr_", "")
fname = "/".join(["css", css_f + ".css"])
urlx = self.report.build_url_fname(fname, None,
self.uplink)
links += Html("link", rel="alternate stylesheet",
title=css_f, indent=False,
media="screen", type="text/css",
href=urlx)
# Link to Navigation Menus stylesheet # Link to Navigation Menus stylesheet
if CSS[self.report.css]["navigation"]: if CSS[self.report.css]["navigation"]:
@ -2977,4 +2991,3 @@ class BasePage: # pylint: disable=C1001
# closes the file # closes the file
self.report.close_file(output_file, sio, date) self.report.close_file(output_file, sio, date)

View File

@ -1008,6 +1008,18 @@ class NavWebReport(Report):
""" """
imgs = [] imgs = []
# copy all screen style sheet
for css_f in CSS:
already_done = False
for css_fn in ("UsEr_", "Basic", "Mainz", "Nebraska", "Vis"):
if css_fn in css_f and not already_done:
already_done = True
fname = CSS[css_f]["filename"]
# add images for this css
imgs += CSS[css_f]["images"]
css_f = css_f.replace("UsEr_", "")
self.copy_file(fname, css_f + ".css", "css")
# copy screen style sheet # copy screen style sheet
if CSS[self.css]["filename"]: if CSS[self.css]["filename"]:
fname = CSS[self.css]["filename"] fname = CSS[self.css]["filename"]
@ -1683,13 +1695,15 @@ class NavWebOptions(MenuReportOptions):
cright.set_help(_("The copyright to be used for the web files")) cright.set_help(_("The copyright to be used for the web files"))
addopt("cright", cright) addopt("cright", cright)
self.__css = EnumeratedListOption(('StyleSheet'), CSS["default"]["id"]) self.__css = EnumeratedListOption(('StyleSheet'),
CSS["Basic-Ash"]["id"])
for (dummy_fname, gid) in sorted( for (dummy_fname, gid) in sorted(
[(CSS[key]["translation"], CSS[key]["id"]) [(CSS[key]["translation"], CSS[key]["id"])
for key in list(CSS.keys())]): for key in list(CSS.keys())]):
if CSS[gid]["user"]: if CSS[gid]["user"]:
self.__css.add_item(CSS[gid]["id"], CSS[gid]["translation"]) self.__css.add_item(CSS[gid]["id"], CSS[gid]["translation"])
self.__css.set_help(_('The stylesheet to be used for the web pages')) self.__css.set_help(_('The default stylesheet to be used for'
' the pages'))
addopt("css", self.__css) addopt("css", self.__css)
self.__css.connect("value-changed", self.__stylesheet_changed) self.__css.connect("value-changed", self.__stylesheet_changed)

View File

@ -348,6 +348,20 @@ class WebCalReport(Report):
""" """
Copies all the necessary stylesheets and images for these calendars Copies all the necessary stylesheets and images for these calendars
""" """
imgs = []
# copy all screen style sheet
for css_f in CSS:
already_done = False
for css_fn in ("UsEr_", "Basic", "Mainz", "Nebraska", "Vis"):
if css_fn in css_f and not already_done:
already_done = True
fname = CSS[css_f]["filename"]
# add images for this css
imgs += CSS[css_f]["images"]
css_f = css_f.replace("UsEr_", "")
self.copy_file(fname, css_f + ".css", "css")
# Copy the screen stylesheet # Copy the screen stylesheet
if self.css and self.css != 'No style sheet': if self.css and self.css != 'No style sheet':
fname = CSS[self.css]["filename"] fname = CSS[self.css]["filename"]
@ -364,8 +378,6 @@ class WebCalReport(Report):
fname = CSS["Print-Default"]["filename"] fname = CSS["Print-Default"]["filename"]
self.copy_file(fname, _CALENDARPRINT, "css") self.copy_file(fname, _CALENDARPRINT, "css")
imgs = []
# Mainz stylesheet graphics # Mainz stylesheet graphics
# will only be used if Mainz is slected as the stylesheet # will only be used if Mainz is slected as the stylesheet
imgs += CSS[self.css]["images"] imgs += CSS[self.css]["images"]
@ -457,7 +469,20 @@ class WebCalReport(Report):
links = Html("link", rel='shortcut icon', links = Html("link", rel='shortcut icon',
href=fname1, type="image/x-icon") + ( href=fname1, type="image/x-icon") + (
Html("link", href=fname2, type="text/css", Html("link", href=fname2, type="text/css",
title=self._("Default"),
media="screen", rel="stylesheet", indent=False)) media="screen", rel="stylesheet", indent=False))
# create all alternate stylesheets
# Cannot use it on local files (file://)
for css_f in CSS:
already_done = False
for css_fn in ("UsEr_", "Basic", "Mainz", "Nebraska"):
if css_fn in css_f and not already_done:
css_f = css_f.replace("UsEr_", "")
fname = "/".join(subdirs + ["css", css_f + ".css"])
links += Html("link", rel="alternate stylesheet",
title=css_f, indent=False,
media="screen", type="text/css",
href=fname)
# add horizontal menu if css == Blue or Visually because # add horizontal menu if css == Blue or Visually because
# there is no menus? # there is no menus?
@ -1390,9 +1415,6 @@ class WebCalReport(Report):
text = short_name text = short_name
self.add_day_item(text, year, month, day, 'Death', self.add_day_item(text, year, month, day, 'Death',
age_at_death, death_date) age_at_death, death_date)
#print('Death date for %s %s/%s/%s' % (short_name, day,
# month, year),
# age_at_death)
# add anniversary if requested # add anniversary if requested
if self.anniv: if self.anniv:
@ -1448,6 +1470,18 @@ class WebCalReport(Report):
wedding_age = first_died - event_date wedding_age = first_died - event_date
wedding_age = wedding_age.format( wedding_age = wedding_age.format(
dlocale=self.rlocale) dlocale=self.rlocale)
divorce_event = get_divorce_event(db, fam)
if divorce_event:
d_date = divorce_event.get_date_object()
if (d_date is not Date() and
d_date.is_valid()):
d_date = gregorian(d_date)
if d_date != Date():
w_age = d_date - event_date
w_age = w_age.format(
dlocale=self.rlocale)
wedding_age = w_age
first_died = d_date
if self.link_to_narweb: if self.link_to_narweb:
prefx = self.narweb_prefix prefx = self.narweb_prefix
@ -1467,8 +1501,8 @@ class WebCalReport(Report):
prob_alive_date) prob_alive_date)
if first_died == Date(): if first_died == Date():
first_died = Date(0, 0, 0) first_died = Date(0, 0, 0)
if ((self.alive and alive1 if ((self.alive and (alive1 or alive2))
and alive2) or not self.alive): or not self.alive):
spse = self._('%(spouse)s and' spse = self._('%(spouse)s and'
' %(person)s') ' %(person)s')
@ -1990,14 +2024,29 @@ def get_marriage_event(db, family):
for event_ref in family.get_event_ref_list(): for event_ref in family.get_event_ref_list():
event = db.get_event_from_handle(event_ref.ref) event = db.get_event_from_handle(event_ref.ref)
if event.type.is_marriage: if event.type.is_marriage():
marriage_event = event marriage_event = event
elif event.type.is_divorce: break
continue
# return the marriage event or False to it caller # return the marriage event or False to it caller
return marriage_event return marriage_event
def get_divorce_event(db, family):
"""
divorce will either be the divorce event or False
"""
divorce_event = False
for event_ref in family.get_event_ref_list():
event = db.get_event_from_handle(event_ref.ref)
if event.type.is_divorce():
divorce_event = event
break
# return the divorce event or False to it caller
return divorce_event
def get_first_day_of_month(year, month): def get_first_day_of_month(year, month):
""" """
Compute the first day to display for this month. Compute the first day to display for this month.

View File

@ -23,6 +23,7 @@
# python modules # python modules
#------------------------------------------------ #------------------------------------------------
import os import os
import re
from gramps.gen.const import VERSION_DIR, IMAGE_DIR, DATA_DIR, USER_CSS from gramps.gen.const import VERSION_DIR, IMAGE_DIR, DATA_DIR, USER_CSS
from gramps.gen.const import GRAMPS_LOCALE as glocale from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext _ = glocale.translation.sgettext
@ -57,125 +58,148 @@ def load_on_reg(dbstate, uistate, plugin):
# default style sheet in the options # default style sheet in the options
# Basic Ash style sheet # Basic Ash style sheet
["default", 1, _("Basic-Ash"), ["Basic-Ash", 1, _("Basic-Ash"),
path_css('Web_Basic-Ash.css'), None, [], [] ], path_css('Web_Basic-Ash.css'), None, [], []],
# Basic Blue style sheet with navigation menus # Basic Blue style sheet with navigation menus
["Basic-Blue", 1, _("Basic-Blue"), ["Basic-Blue", 1, _("Basic-Blue"),
path_css('Web_Basic-Blue.css'), None, [], [] ], path_css('Web_Basic-Blue.css'), None, [], []],
# Basic Cypress style sheet # Basic Cypress style sheet
["Basic-Cypress", 1, _("Basic-Cypress"), ["Basic-Cypress", 1, _("Basic-Cypress"),
path_css('Web_Basic-Cypress.css'), None, [], [] ], path_css('Web_Basic-Cypress.css'), None, [], []],
# basic Lilac style sheet # basic Lilac style sheet
["Basic-Lilac", 1, _("Basic-Lilac"), ["Basic-Lilac", 1, _("Basic-Lilac"),
path_css('Web_Basic-Lilac.css'), None, [], [] ], path_css('Web_Basic-Lilac.css'), None, [], []],
# basic Peach style sheet # basic Peach style sheet
["Basic-Peach", 1, _("Basic-Peach"), ["Basic-Peach", 1, _("Basic-Peach"),
path_css('Web_Basic-Peach.css'), None, [], [] ], path_css('Web_Basic-Peach.css'), None, [], []],
# basic Spruce style sheet # basic Spruce style sheet
["Basic-Spruce", 1, _("Basic-Spruce"), ["Basic-Spruce", 1, _("Basic-Spruce"),
path_css('Web_Basic-Spruce.css'), None, [], [] ], path_css('Web_Basic-Spruce.css'), None, [], []],
# Mainz style sheet with its images # Mainz style sheet with its images
["Mainz", 1, _("Mainz"), ["Mainz", 1, _("Mainz"),
path_css('Web_Mainz.css'), None, path_css('Web_Mainz.css'), None,
[path_img("Web_Mainz_Bkgd.png"), [path_img("Web_Mainz_Bkgd.png"),
path_img("Web_Mainz_Header.png"), path_img("Web_Mainz_Header.png"),
path_img("Web_Mainz_Mid.png"), path_img("Web_Mainz_Mid.png"),
path_img("Web_Mainz_MidLight.png")], [] ], path_img("Web_Mainz_MidLight.png")], []],
# Nebraska style sheet # Nebraska style sheet
["Nebraska", 1, _("Nebraska"), ["Nebraska", 1, _("Nebraska"),
path_css('Web_Nebraska.css'), None, [], [] ], path_css('Web_Nebraska.css'), None, [], []],
# Visually Impaired style sheet with its navigation menus # Visually Impaired style sheet with its navigation menus
["Visually Impaired", 1, _("Visually Impaired"), ["Visually Impaired", 1, _("Visually Impaired"),
path_css('Web_Visually.css'), "narrative-menus.css", [], [] ], path_css('Web_Visually.css'), "narrative-menus.css", [], []],
# ancestor tree style sheet and its images # ancestor tree style sheet and its images
["ancestortree", 0, "ancestortree", ["ancestortree", 0, "ancestortree",
path_css("ancestortree.css"), None, path_css("ancestortree.css"), None,
[path_img("Web_Gender_Female.png"), [path_img("Web_Gender_Female.png"),
path_img("Web_Gender_Male.png")], [] ], path_img("Web_Gender_Male.png")], []],
# media reference regions style sheet # media reference regions style sheet
["behaviour", 0, "Behaviour", ["behaviour", 0, "Behaviour",
path_css('behaviour.css'), None, [], [] ], path_css('behaviour.css'), None, [], []],
# NarrativeMap stylesheet/ image for NarrativeWeb place maps # NarrativeMap stylesheet/ image for NarrativeWeb place maps
["NarrativeMaps", 0, "", ["NarrativeMaps", 0, "",
path_css("narrative-maps.css"), None, [], [] ], path_css("narrative-maps.css"), None, [], []],
# default printer style sheet # default printer style sheet
["Print-Default", 0, "Print-Default", ["Print-Default", 0, "Print-Default",
path_css('Web_Print-Default.css'), None, [], [] ], path_css('Web_Print-Default.css'), None, [], []],
# Horizontal Navigation Menus Style Sheet # Horizontal Navigation Menus Style Sheet
["Horizontal-Menus", 0, "Horizontal Menus", ["Horizontal-Menus", 0, "Horizontal Menus",
path_css('Web_Horizontal-Menus.css'), None, [], [] ], path_css('Web_Horizontal-Menus.css'), None, [], []],
# Vertical Navigation Menus Style Sheet # Vertical Navigation Menus Style Sheet
["Vertical-Menus", 0, "Vertical Menus", ["Vertical-Menus", 0, "Vertical Menus",
path_css('Web_Vertical-Menus.css'), None, [], [] ], path_css('Web_Vertical-Menus.css'), None, [], []],
# WebKit/ Html5/ CSS3 Fade Navigation Menus Style Sheet # WebKit/ Html5/ CSS3 Fade Navigation Menus Style Sheet
["Fade-Menus", 0, "Fade In/ Out Menus", ["Fade-Menus", 0, "Fade In/ Out Menus",
path_css('Web_Fade-Menus.css'), None, [], [] ], path_css('Web_Fade-Menus.css'), None, [], []],
# WebKit/ Html5/ CSS3 Animated Drop Down Style Sheet # WebKit/ Html5/ CSS3 Animated Drop Down Style Sheet
["Animated DropDown", 0, "Animated DropDown", ["Animated DropDown", 0, "Animated DropDown",
path_css("Web_Citations-Animated.css"), None, [], path_css("Web_Citations-Animated.css"), None, [],
"https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" ], "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"],
# Source Page Citations Referents Outline Style sheet... # Source Page Citations Referents Outline Style sheet...
["Outline", 0, "Outline Citations", ["Outline", 0, "Outline Citations",
path_css("Web_Citations-Outline.css"), None, [], [] ], path_css("Web_Citations-Outline.css"), None, [], []],
# WebKit/ Html5/ CSS3 Drop Down Navigation Menus Style Sheet # WebKit/ Html5/ CSS3 Drop Down Navigation Menus Style Sheet
["DropDown-Menus", 0, "Drop Down Menus", ["DropDown-Menus", 0, "Drop Down Menus",
path_css("Web_DropDown-Menus.css"), None, [], [] ], path_css("Web_DropDown-Menus.css"), None, [], []],
# no style sheet option # no style sheet option
["No style sheet",1, _("No style sheet"), [], None, [], [] ], ["No style sheet", 1, _("No style sheet"), [], None, [], []],
# Document image # Document image
["Document", 0, "Document", ["Document", 0, "Document",
os.path.join(IMAGE_DIR, "document.png"), None, [], [] ], os.path.join(IMAGE_DIR, "document.png"), None, [], []],
# blank # blank
["Blank", 0, "Blank", ["Blank", 0, "Blank",
path_img("blank.gif"), None, [], [] ], path_img("blank.gif"), None, [], []],
# all other images for use in NarrativeWeb # all other images for use in NarrativeWeb
['All Images', 0, 'All Images', None, None, ['All Images', 0, 'All Images', None, None,
[path_img("blank.gif"), [path_img("blank.gif"),
os.path.join(IMAGE_DIR, "document.png")], [] ], os.path.join(IMAGE_DIR, "document.png")], []],
# Gramps Fav icon #2 # Gramps Fav icon #2
["favicon2", 0, "FavIcon2", ["favicon2", 0, "FavIcon2",
path_img("favicon2.ico"), None, [], [] ], path_img("favicon2.ico"), None, [], []],
# copyright image # copyright image
['Copyright', 0, 'Copyright', ['Copyright', 0, 'Copyright',
path_img("somerights20.gif"), None, [], [] ], path_img("somerights20.gif"), None, [], []],
# marker icon for openstreetmap # marker icon for openstreetmap
['marker', 0, 'marker', ['marker', 0, 'marker',
path_img_48x48("gramps-geo-mainmap.png"), None, [], [] ], path_img_48x48("gramps-geo-mainmap.png"), None, [], []],
] ]
# If we add css user files, we must restart gramps to use them. # If we add css user files, we must restart gramps to use them.
if os.path.exists(USER_CSS): if os.path.exists(USER_CSS):
list_files = os.listdir(USER_CSS) list_files = os.listdir(USER_CSS)
for cssfile in list_files: for cssfile in list_files:
CSS_FILES.append([cssfile, 1, cssfile.replace('.css', ''), if cssfile.endswith(".css"):
os.path.join(USER_CSS,cssfile), css_f = cssfile.replace('.css', '')
None, [], [] ]) CSS_FILES.append(["UsEr_" + css_f, 1, css_f,
os.path.join(USER_CSS, cssfile), None,
looking_for_urls_in_user_css(cssfile),
[]])
return CSS_FILES return CSS_FILES
def looking_for_urls_in_user_css(css_file):
"""
At each time we find the tag url, we get the content and add it
to the images list. This content must be local.
"""
images = []
cssfile = os.path.join(USER_CSS, css_file)
with open(cssfile) as css:
data = css.readlines()
for line in data:
if "url" in line:
url = re.match(r".*url\((.*)\)", line)
if url.group(1)[0:3] != "http":
img = url.group(1).replace("../images/", "")
img = os.path.join(USER_CSS, img)
if img not in images:
images.append('%s' % img)
return images
def process_list(data): def process_list(data):
""" """
Gather all of the web resources together, and allow override files Gather all of the web resources together, and allow override files
@ -185,7 +209,7 @@ def process_list(data):
for row in data: for row in data:
file = row[3] file = row[3]
if file: if file:
path, filename = os.path.split(file) dummy_path, filename = os.path.split(file)
# is there a override file in the VERSION_DIR/webstuff? # is there a override file in the VERSION_DIR/webstuff?
# eg, ~/.gramps/gramps34/webstuff/Web_Nebraska.css # eg, ~/.gramps/gramps34/webstuff/Web_Nebraska.css
# if so, replace this one: # if so, replace this one: