mirror of
https://github.com/ejwa/gitinspector.git
synced 2025-01-03 11:22:15 +01:00
Added support for gravatars in the changes, blame and timeline modules.
References to gravatar images are generated with HTML and XML outputs only as these are the only formats where referencing gravatars makes sense right now. The HTMLEmbedded format, for example, does not link to any gravatars as that format prohibits the use of external links. To accommodate the new images; the width of the generated HTML page has been slightly increased. However, the HTML page should still fit on a 1280 display.
This commit is contained in:
parent
d07da3dc69
commit
35852f9859
6 changed files with 128 additions and 44 deletions
|
@ -25,6 +25,7 @@ from changes import FileDiff
|
||||||
import comment
|
import comment
|
||||||
import filtering
|
import filtering
|
||||||
import format
|
import format
|
||||||
|
import gravatar
|
||||||
import interval
|
import interval
|
||||||
import missing
|
import missing
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
@ -61,16 +62,16 @@ class BlameThread(threading.Thread):
|
||||||
for j in git_blame_r.readlines():
|
for j in git_blame_r.readlines():
|
||||||
j = j.decode("utf-8", "replace")
|
j = j.decode("utf-8", "replace")
|
||||||
if Blame.is_blame_line(j):
|
if Blame.is_blame_line(j):
|
||||||
author = Blame.get_author(j)
|
author_mail = Blame.get_author_mail(j)
|
||||||
content = Blame.get_content(j)
|
content = Blame.get_content(j)
|
||||||
__blame_lock__.acquire() # Global lock used to protect calls from here...
|
__blame_lock__.acquire() # Global lock used to protect calls from here...
|
||||||
|
|
||||||
if self.blames.get((author, self.filename), None) == None:
|
if self.blames.get((author_mail, self.filename), None) == None:
|
||||||
self.blames[(author, self.filename)] = BlameEntry()
|
self.blames[(author_mail, self.filename)] = BlameEntry()
|
||||||
|
|
||||||
(comments, is_inside_comment) = comment.handle_comment_block(is_inside_comment, self.extension, content)
|
(comments, is_inside_comment) = comment.handle_comment_block(is_inside_comment, self.extension, content)
|
||||||
self.blames[(author, self.filename)].comments += comments
|
self.blames[(author_mail, self.filename)].comments += comments
|
||||||
self.blames[(author, self.filename)].rows += 1
|
self.blames[(author_mail, self.filename)].rows += 1
|
||||||
__blame_lock__.release() # ...to here.
|
__blame_lock__.release() # ...to here.
|
||||||
|
|
||||||
git_blame_r.close()
|
git_blame_r.close()
|
||||||
|
@ -92,7 +93,7 @@ class Blame:
|
||||||
|
|
||||||
if FileDiff.is_valid_extension(row) and not filtering.set_filtered(FileDiff.get_filename(row)):
|
if FileDiff.is_valid_extension(row) and not filtering.set_filtered(FileDiff.get_filename(row)):
|
||||||
if not missing.add(row):
|
if not missing.add(row):
|
||||||
blame_string = "git blame -w {0} ".format("-C -C -M" if hard else "") + \
|
blame_string = "git blame -e -w {0} ".format("-C -C -M" if hard else "") + \
|
||||||
interval.get_since() + interval.get_ref() + " -- \"" + row + "\""
|
interval.get_since() + interval.get_ref() + " -- \"" + row + "\""
|
||||||
thread = BlameThread(blame_string, FileDiff.get_extension(row), self.blames, row.strip())
|
thread = BlameThread(blame_string, FileDiff.get_extension(row), self.blames, row.strip())
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
|
@ -117,9 +118,9 @@ class Blame:
|
||||||
return string.find(" (") != -1
|
return string.find(" (") != -1
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_author(string):
|
def get_author_mail(string):
|
||||||
author = re.search(" \((.*?)\d\d\d\d-\d\d-\d\d", string)
|
author_mail = re.search(" \((.*?)\d\d\d\d-\d\d-\d\d", string)
|
||||||
return author.group(1).strip()
|
return author_mail.group(1).strip().lstrip("<").rstrip(">")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_content(string):
|
def get_content(string):
|
||||||
|
@ -150,8 +151,9 @@ BLAME_INFO_TEXT = N_("Below are the number of rows from each author that have su
|
||||||
"intact in the current revision")
|
"intact in the current revision")
|
||||||
|
|
||||||
class BlameOutput(Outputable):
|
class BlameOutput(Outputable):
|
||||||
def __init__(self, hard):
|
def __init__(self, changes, hard):
|
||||||
self.hard = hard
|
self.hard = hard
|
||||||
|
self.changes = changes
|
||||||
Outputable.__init__(self)
|
Outputable.__init__(self)
|
||||||
|
|
||||||
def output_html(self):
|
def output_html(self):
|
||||||
|
@ -171,14 +173,20 @@ class BlameOutput(Outputable):
|
||||||
|
|
||||||
for i, entry in enumerate(blames):
|
for i, entry in enumerate(blames):
|
||||||
work_percentage = str("{0:.2f}".format(100.0 * entry[1].rows / total_blames))
|
work_percentage = str("{0:.2f}".format(100.0 * entry[1].rows / total_blames))
|
||||||
|
authorname = self.changes.get_authorname_from_email(entry[0])
|
||||||
|
|
||||||
blame_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
blame_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
||||||
blame_xml += "<td>" + entry[0] + "</td>"
|
|
||||||
|
if format.get_selected() == "html":
|
||||||
|
blame_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(entry[0]), authorname)
|
||||||
|
else:
|
||||||
|
blame_xml += "<td>" + authorname + "</td>"
|
||||||
|
|
||||||
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
|
blame_xml += "<td>" + str(entry[1].rows) + "</td>"
|
||||||
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
|
blame_xml += "<td>" + "{0:.2f}".format(100.0 * entry[1].comments / entry[1].rows) + "</td>"
|
||||||
blame_xml += "<td style=\"display: none\">" + work_percentage + "</td>"
|
blame_xml += "<td style=\"display: none\">" + work_percentage + "</td>"
|
||||||
blame_xml += "</tr>"
|
blame_xml += "</tr>"
|
||||||
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry[0], work_percentage)
|
chart_data += "{{label: \"{0}\", data: {1}}}".format(authorname, work_percentage)
|
||||||
|
|
||||||
if blames[-1] != entry:
|
if blames[-1] != entry:
|
||||||
chart_data += ", "
|
chart_data += ", "
|
||||||
|
@ -214,7 +222,8 @@ class BlameOutput(Outputable):
|
||||||
print(textwrap.fill(_(BLAME_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
|
print(textwrap.fill(_(BLAME_INFO_TEXT) + ":", width=terminal.get_size()[0]) + "\n")
|
||||||
terminal.printb(_("Author").ljust(21) + _("Rows").rjust(10) + _("% in comments").rjust(20))
|
terminal.printb(_("Author").ljust(21) + _("Rows").rjust(10) + _("% in comments").rjust(20))
|
||||||
for i in sorted(__blame__.get_summed_blames().items()):
|
for i in sorted(__blame__.get_summed_blames().items()):
|
||||||
print(i[0].ljust(20)[0:20], end=" ")
|
authorname = self.changes.get_authorname_from_email(i[0])
|
||||||
|
print(authorname.ljust(20)[0:20], end=" ")
|
||||||
print(str(i[1].rows).rjust(10), end=" ")
|
print(str(i[1].rows).rjust(10), end=" ")
|
||||||
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(19))
|
print("{0:.2f}".format(100.0 * i[1].comments / i[1].rows).rjust(19))
|
||||||
|
|
||||||
|
@ -225,10 +234,12 @@ class BlameOutput(Outputable):
|
||||||
blame_xml = ""
|
blame_xml = ""
|
||||||
|
|
||||||
for i in sorted(__blame__.get_summed_blames().items()):
|
for i in sorted(__blame__.get_summed_blames().items()):
|
||||||
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n"
|
authorname = self.changes.get_authorname_from_email(i[0])
|
||||||
|
name_xml = "\t\t\t\t<name>" + authorname + "</name>\n"
|
||||||
|
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(i[0]) + "</gravatar>\n"
|
||||||
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
|
rows_xml = "\t\t\t\t<rows>" + str(i[1].rows) + "</rows>\n"
|
||||||
percentage_in_comments_xml = ("\t\t\t\t<percentage-in-comments>" + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +
|
percentage_in_comments_xml = ("\t\t\t\t<percentage-in-comments>" + "{0:.2f}".format(100.0 * i[1].comments / i[1].rows) +
|
||||||
"</percentage-in-comments>\n")
|
"</percentage-in-comments>\n")
|
||||||
blame_xml += "\t\t\t<author>\n" + name_xml + rows_xml + percentage_in_comments_xml + "\t\t\t</author>\n"
|
blame_xml += "\t\t\t<author>\n" + name_xml + gravatar_xml + rows_xml + percentage_in_comments_xml + "\t\t\t</author>\n"
|
||||||
|
|
||||||
print("\t<blame>\n" + message_xml + "\t\t<authors>\n" + blame_xml + "\t\t</authors>\n\t</blame>")
|
print("\t<blame>\n" + message_xml + "\t\t<authors>\n" + blame_xml + "\t\t</authors>\n\t</blame>")
|
||||||
|
|
|
@ -23,6 +23,8 @@ from localization import N_
|
||||||
from outputable import Outputable
|
from outputable import Outputable
|
||||||
import extensions
|
import extensions
|
||||||
import filtering
|
import filtering
|
||||||
|
import format
|
||||||
|
import gravatar
|
||||||
import interval
|
import interval
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -66,10 +68,11 @@ class Commit:
|
||||||
self.filediffs = []
|
self.filediffs = []
|
||||||
commit_line = string.split("|")
|
commit_line = string.split("|")
|
||||||
|
|
||||||
if commit_line.__len__() == 3:
|
if commit_line.__len__() == 4:
|
||||||
self.date = commit_line[0]
|
self.date = commit_line[0]
|
||||||
self.sha = commit_line[1]
|
self.sha = commit_line[1]
|
||||||
self.author = commit_line[2].strip()
|
self.author = commit_line[2].strip()
|
||||||
|
self.email = commit_line[3].strip()
|
||||||
|
|
||||||
def add_filediff(self, filediff):
|
def add_filediff(self, filediff):
|
||||||
self.filediffs.append(filediff)
|
self.filediffs.append(filediff)
|
||||||
|
@ -79,7 +82,7 @@ class Commit:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_commit_line(string):
|
def is_commit_line(string):
|
||||||
return string.split("|").__len__() == 3
|
return string.split("|").__len__() == 4
|
||||||
|
|
||||||
class AuthorInfo:
|
class AuthorInfo:
|
||||||
insertions = 0
|
insertions = 0
|
||||||
|
@ -87,9 +90,12 @@ class AuthorInfo:
|
||||||
commits = 0
|
commits = 0
|
||||||
|
|
||||||
class Changes:
|
class Changes:
|
||||||
|
authors = {}
|
||||||
|
authors_dateinfo = {}
|
||||||
|
|
||||||
def __init__(self, hard):
|
def __init__(self, hard):
|
||||||
self.commits = []
|
self.commits = []
|
||||||
git_log_r = subprocess.Popen("git log --pretty=\"%cd|%H|%aN\" --stat=100000,8192 --no-merges -w " +
|
git_log_r = subprocess.Popen("git log --pretty=\"%cd|%H|%aN|%aE\" --stat=100000,8192 --no-merges -w " +
|
||||||
interval.get_since() + interval.get_until() +
|
interval.get_since() + interval.get_until() +
|
||||||
"{0} --date=short".format("-C -C -M" if hard else ""),
|
"{0} --date=short".format("-C -C -M" if hard else ""),
|
||||||
shell=True, bufsize=1, stdout=subprocess.PIPE).stdout
|
shell=True, bufsize=1, stdout=subprocess.PIPE).stdout
|
||||||
|
@ -136,18 +142,28 @@ class Changes:
|
||||||
authors[key].deletions += j.deletions
|
authors[key].deletions += j.deletions
|
||||||
|
|
||||||
def get_authorinfo_list(self):
|
def get_authorinfo_list(self):
|
||||||
authors = {}
|
if not self.authors:
|
||||||
for i in self.commits:
|
for i in self.commits:
|
||||||
Changes.__modify_authorinfo__(authors, i.author, i)
|
Changes.__modify_authorinfo__(self.authors, (i.author, i.email), i)
|
||||||
|
|
||||||
return authors
|
return self.authors
|
||||||
|
|
||||||
def get_authordateinfo_list(self):
|
def get_authordateinfo_list(self):
|
||||||
authors = {}
|
if not self.authors_dateinfo:
|
||||||
for i in self.commits:
|
for i in self.commits:
|
||||||
Changes.__modify_authorinfo__(authors, (i.date, i.author), i)
|
Changes.__modify_authorinfo__(self.authors_dateinfo, (i.date, i.author, i.email), i)
|
||||||
|
|
||||||
return authors
|
return self.authors_dateinfo
|
||||||
|
|
||||||
|
def get_authorname_from_email(self, email):
|
||||||
|
if not self.authors:
|
||||||
|
get_authorinfo_list(self)
|
||||||
|
|
||||||
|
for author in self.authors:
|
||||||
|
if author[1] == email:
|
||||||
|
return author[0]
|
||||||
|
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
__changes__ = None
|
__changes__ = None
|
||||||
|
|
||||||
|
@ -187,13 +203,18 @@ class ChangesOutput(Outputable):
|
||||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||||
|
|
||||||
changes_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
changes_xml += "<tr " + ("class=\"odd\">" if i % 2 == 1 else ">")
|
||||||
changes_xml += "<td>" + entry + "</td>"
|
|
||||||
|
if format.get_selected() == "html":
|
||||||
|
changes_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(entry[1]), entry[0])
|
||||||
|
else:
|
||||||
|
changes_xml += "<td>" + entry[0] + "</td>"
|
||||||
|
|
||||||
changes_xml += "<td>" + str(authorinfo.commits) + "</td>"
|
changes_xml += "<td>" + str(authorinfo.commits) + "</td>"
|
||||||
changes_xml += "<td>" + str(authorinfo.insertions) + "</td>"
|
changes_xml += "<td>" + str(authorinfo.insertions) + "</td>"
|
||||||
changes_xml += "<td>" + str(authorinfo.deletions) + "</td>"
|
changes_xml += "<td>" + str(authorinfo.deletions) + "</td>"
|
||||||
changes_xml += "<td>" + "{0:.2f}".format(percentage) + "</td>"
|
changes_xml += "<td>" + "{0:.2f}".format(percentage) + "</td>"
|
||||||
changes_xml += "</tr>"
|
changes_xml += "</tr>"
|
||||||
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry, "{0:.2f}".format(percentage))
|
chart_data += "{{label: \"{0}\", data: {1}}}".format(entry[0], "{0:.2f}".format(percentage))
|
||||||
|
|
||||||
if sorted(authorinfo_list)[-1] != entry:
|
if sorted(authorinfo_list)[-1] != entry:
|
||||||
chart_data += ", "
|
chart_data += ", "
|
||||||
|
@ -239,7 +260,7 @@ class ChangesOutput(Outputable):
|
||||||
authorinfo = authorinfo_list.get(i)
|
authorinfo = authorinfo_list.get(i)
|
||||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||||
|
|
||||||
print(i.ljust(20)[0:20], end=" ")
|
print(i[0].ljust(20)[0:20], end=" ")
|
||||||
print(str(authorinfo.commits).rjust(13), end=" ")
|
print(str(authorinfo.commits).rjust(13), end=" ")
|
||||||
print(str(authorinfo.insertions).rjust(13), end=" ")
|
print(str(authorinfo.insertions).rjust(13), end=" ")
|
||||||
print(str(authorinfo.deletions).rjust(14), end=" ")
|
print(str(authorinfo.deletions).rjust(14), end=" ")
|
||||||
|
@ -262,14 +283,14 @@ class ChangesOutput(Outputable):
|
||||||
for i in sorted(authorinfo_list):
|
for i in sorted(authorinfo_list):
|
||||||
authorinfo = authorinfo_list.get(i)
|
authorinfo = authorinfo_list.get(i)
|
||||||
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
percentage = 0 if total_changes == 0 else (authorinfo.insertions + authorinfo.deletions) / total_changes * 100
|
||||||
|
name_xml = "\t\t\t\t<name>" + i[0] + "</name>\n"
|
||||||
name_xml = "\t\t\t\t<name>" + i + "</name>\n"
|
gravatar_xml = "\t\t\t\t<gravatar>" + gravatar.get_url(i[1]) + "</gravatar>\n"
|
||||||
commits_xml = "\t\t\t\t<commits>" + str(authorinfo.commits) + "</commits>\n"
|
commits_xml = "\t\t\t\t<commits>" + str(authorinfo.commits) + "</commits>\n"
|
||||||
insertions_xml = "\t\t\t\t<insertions>" + str(authorinfo.insertions) + "</insertions>\n"
|
insertions_xml = "\t\t\t\t<insertions>" + str(authorinfo.insertions) + "</insertions>\n"
|
||||||
deletions_xml = "\t\t\t\t<deletions>" + str(authorinfo.deletions) + "</deletions>\n"
|
deletions_xml = "\t\t\t\t<deletions>" + str(authorinfo.deletions) + "</deletions>\n"
|
||||||
percentage_xml = "\t\t\t\t<percentage-of-changes>" + "{0:.2f}".format(percentage) + "</percentage-of-changes>\n"
|
percentage_xml = "\t\t\t\t<percentage-of-changes>" + "{0:.2f}".format(percentage) + "</percentage-of-changes>\n"
|
||||||
|
|
||||||
changes_xml += ("\t\t\t<author>\n" + name_xml + commits_xml + insertions_xml +
|
changes_xml += ("\t\t\t<author>\n" + name_xml + gravatar_xml + commits_xml + insertions_xml +
|
||||||
deletions_xml + percentage_xml + "\t\t\t</author>\n")
|
deletions_xml + percentage_xml + "\t\t\t</author>\n")
|
||||||
|
|
||||||
print("\t<changes>\n" + message_xml + "\t\t<authors>\n" + changes_xml + "\t\t</authors>\n\t</changes>")
|
print("\t<changes>\n" + message_xml + "\t\t<authors>\n" + changes_xml + "\t\t</authors>\n\t</changes>")
|
||||||
|
|
|
@ -78,7 +78,7 @@ class Runner:
|
||||||
outputable.output(changes.ChangesOutput(self.hard))
|
outputable.output(changes.ChangesOutput(self.hard))
|
||||||
|
|
||||||
if changes.get(self.hard).get_commits():
|
if changes.get(self.hard).get_commits():
|
||||||
outputable.output(blame.BlameOutput(self.hard))
|
outputable.output(blame.BlameOutput(changes.get(self.hard), self.hard))
|
||||||
|
|
||||||
if self.timeline:
|
if self.timeline:
|
||||||
outputable.output(timeline.Timeline(changes.get(self.hard), self.useweeks))
|
outputable.output(timeline.Timeline(changes.get(self.hard), self.useweeks))
|
||||||
|
|
34
gitinspector/gravatar.py
Normal file
34
gitinspector/gravatar.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# coding: utf-8
|
||||||
|
#
|
||||||
|
# Copyright © 2013 Ejwa Software. All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is part of gitinspector.
|
||||||
|
#
|
||||||
|
# gitinspector is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# gitinspector is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with gitinspector. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import format
|
||||||
|
import hashlib
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
def get_url(email):
|
||||||
|
md5hash = hashlib.md5(email.lower().strip()).hexdigest()
|
||||||
|
base_url = "http://www.gravatar.com/avatar/" + md5hash
|
||||||
|
params = None
|
||||||
|
|
||||||
|
if format.get_selected() == "html":
|
||||||
|
params = {"default": "identicon", "size": 20}
|
||||||
|
elif format.get_selected() == "xml":
|
||||||
|
params = {"default": "identicon"}
|
||||||
|
|
||||||
|
return base_url + "?" + urllib.urlencode(params)
|
|
@ -128,7 +128,7 @@
|
||||||
}}
|
}}
|
||||||
body > div {{
|
body > div {{
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 50em;
|
width: 58em;
|
||||||
}}
|
}}
|
||||||
div.box {{
|
div.box {{
|
||||||
border: 4px solid #ddd;
|
border: 4px solid #ddd;
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
}}
|
}}
|
||||||
table.git {{
|
table.git {{
|
||||||
font-size: small;
|
font-size: small;
|
||||||
width: 60%;
|
width: 65%;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
}}
|
}}
|
||||||
table.full {{
|
table.full {{
|
||||||
|
@ -179,9 +179,9 @@
|
||||||
-moz-border-radius: 0px 0px 8px 8px;
|
-moz-border-radius: 0px 0px 8px 8px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}}
|
}}
|
||||||
table.git td {{
|
table.git td, table.git th, table#timeline td, table#timeline th {{
|
||||||
padding: 0.4em;
|
padding: 0.35em;
|
||||||
height: 1em;
|
height: 2em;
|
||||||
}}
|
}}
|
||||||
table.git td div.insert {{
|
table.git td div.insert {{
|
||||||
background-color: #7a7;
|
background-color: #7a7;
|
||||||
|
@ -204,7 +204,7 @@
|
||||||
top: 5px;
|
top: 5px;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
width: 40%;
|
width: 35%;
|
||||||
font-size: x-small;
|
font-size: x-small;
|
||||||
height: 210px;
|
height: 210px;
|
||||||
}}
|
}}
|
||||||
|
@ -227,6 +227,15 @@
|
||||||
border: 1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
cursor: hand;
|
cursor: hand;
|
||||||
}}
|
}}
|
||||||
|
td img {{
|
||||||
|
border-radius: 3px 3px 3px 3px;
|
||||||
|
-moz-border-radius: 3px 3px 3px 3px;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
opacity: 0.85;
|
||||||
|
}}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -22,6 +22,8 @@ from __future__ import unicode_literals
|
||||||
from localization import N_
|
from localization import N_
|
||||||
from outputable import Outputable
|
from outputable import Outputable
|
||||||
import datetime
|
import datetime
|
||||||
|
import format
|
||||||
|
import gravatar
|
||||||
import terminal
|
import terminal
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
@ -37,9 +39,9 @@ class TimelineData:
|
||||||
|
|
||||||
if useweeks:
|
if useweeks:
|
||||||
yearweek = datetime.date(int(i[0][0][0:4]), int(i[0][0][5:7]), int(i[0][0][8:10])).isocalendar()
|
yearweek = datetime.date(int(i[0][0][0:4]), int(i[0][0][5:7]), int(i[0][0][8:10])).isocalendar()
|
||||||
key = (i[0][1], str(yearweek[0]) + "W" + "{0:02d}".format(yearweek[1]))
|
key = ((i[0][1], i[0][2]), str(yearweek[0]) + "W" + "{0:02d}".format(yearweek[1]))
|
||||||
else:
|
else:
|
||||||
key = (i[0][1], i[0][0][0:7])
|
key = ((i[0][1], i[0][2]), i[0][0][0:7])
|
||||||
|
|
||||||
if self.entries.get(key, None) == None:
|
if self.entries.get(key, None) == None:
|
||||||
self.entries[key] = i[1]
|
self.entries[key] = i[1]
|
||||||
|
@ -117,7 +119,7 @@ def __output_row__text__(timeline_data, periods, names):
|
||||||
|
|
||||||
for name in names:
|
for name in names:
|
||||||
if timeline_data.is_author_in_periods(periods, name):
|
if timeline_data.is_author_in_periods(periods, name):
|
||||||
print(name.ljust(20)[0:20], end=" ")
|
print(name[0].ljust(20)[0:20], end=" ")
|
||||||
for period in periods:
|
for period in periods:
|
||||||
multiplier = timeline_data.get_multiplier(period, 9)
|
multiplier = timeline_data.get_multiplier(period, 9)
|
||||||
signs = timeline_data.get_author_signs_in_period(name, period, multiplier)
|
signs = timeline_data.get_author_signs_in_period(name, period, multiplier)
|
||||||
|
@ -146,7 +148,13 @@ def __output_row__html__(timeline_data, periods, names):
|
||||||
for name in names:
|
for name in names:
|
||||||
if timeline_data.is_author_in_periods(periods, name):
|
if timeline_data.is_author_in_periods(periods, name):
|
||||||
timeline_xml += "<tr" + (" class=\"odd\">" if i % 2 == 1 else ">")
|
timeline_xml += "<tr" + (" class=\"odd\">" if i % 2 == 1 else ">")
|
||||||
timeline_xml += "<td>" + name + "</td>"
|
#timeline_xml += "<td>" + name[0] + "</td>"
|
||||||
|
|
||||||
|
if format.get_selected() == "html":
|
||||||
|
timeline_xml += "<td><img src=\"{0}\"/>{1}</td>".format(gravatar.get_url(name[1]), name[0])
|
||||||
|
else:
|
||||||
|
timeline_xml += "<td>" + name[0] + "</td>"
|
||||||
|
|
||||||
for period in periods:
|
for period in periods:
|
||||||
multiplier = timeline_data.get_multiplier(period, 14)
|
multiplier = timeline_data.get_multiplier(period, 14)
|
||||||
signs = timeline_data.get_author_signs_in_period(name, period, multiplier)
|
signs = timeline_data.get_author_signs_in_period(name, period, multiplier)
|
||||||
|
@ -225,7 +233,8 @@ class Timeline(Outputable):
|
||||||
if len(signs_str) == 0:
|
if len(signs_str) == 0:
|
||||||
signs_str = "."
|
signs_str = "."
|
||||||
|
|
||||||
authors_xml += "\t\t\t\t\t<author>\n\t\t\t\t\t\t<name>" + name + "</name>\n"
|
authors_xml += "\t\t\t\t\t<author>\n\t\t\t\t\t\t<name>" + name[0] + "</name>\n"
|
||||||
|
authors_xml += "\t\t\t\t\t\t<gravatar>" + gravatar.get_url(name[1]) + "</gravatar>\n"
|
||||||
authors_xml += "\t\t\t\t\t\t<work>" + signs_str + "</work>\n\t\t\t\t\t</author>\n"
|
authors_xml += "\t\t\t\t\t\t<work>" + signs_str + "</work>\n\t\t\t\t\t</author>\n"
|
||||||
|
|
||||||
authors_xml += "\t\t\t\t</authors>\n"
|
authors_xml += "\t\t\t\t</authors>\n"
|
||||||
|
|
Loading…
Reference in a new issue