From: John 'Warthog9' Hawley <warthog9@xxxxxxxxxxxxxx> This patch is based on Kevin Cernekee's <cernekee@xxxxxxxxx> patch series entitled "gitweb: introduce localtime feature". While Kevin's patch changed the server side output so that the timezone was output from gitweb itself, this has a number of drawbacks, in particular with respect to gitweb-caching. This patch takes the same basic goal, display the appropriate times in a given common timezone, and implements it in JavaScript. This requires adding / using a new class, "datetime", to be able to find elements to be adjusted from JavaScript. Appropriate dates are wrapped in a span with this class. Timezone to be used can be retrieved from "gitweb_tz" cookie, though currently there is no way to set / manipulate this cookie from gitweb; this is left for later commit. Valid timezones, currently, are: "utc", "local" (which means that timezone is taken from browser), and "+/-ZZZZ" numeric timezone as in RFC-2822. Default timezone is "local" (currently not configurable, left for later commit). Fallback (should JavaScript not be enabled) is to treat dates as they have been and display them, only, in UTC. Pages affected: * 'summary' view, "last change" field (commit time from latest change) * 'log' view, author time * 'commit' and 'commitdiff' views, author/committer time * 'tag' view, tagger time Based-on-code-from: Kevin Cernekee <cernekee@xxxxxxxxx> Signed-off-by: John 'Warthog9' Hawley <warthog9@xxxxxxxxxxxxxx> Signed-off-by: Jakub Narebski <jnareb@xxxxxxxxx> --- The only change from v2 is that we used epoch = parseRFC2822Date(curElement.innerHTML); now we use epoch = parseRFC2822Date(curElement.firstChild.data); This is because of two reasons: * it futureproofs fixDatetimeTZ() against eventual changes in structure of gitweb output (of contents of "span.datetime"), like e.g. timezone selection menu not deleted but only made invisible. * it is more consistent, because we have to use .firstChild.data instead of .innerHTML for setting, as the latter doesn't work for Mozilla 1.17.2 in [overly] strict settings (XHTML DOM + application/xml+xhtml mimetype). ... This is major part of J.H. patch. NOTE that while major ideas (and some of names) are taken from J.H. patch, the code was practically written anew from scratch. I avoid using global variables, as recommended in various tips for better JavaScript performance. Global variables are discouraged anyway... Actual interface for changing / selecting timezone is left for later commit, both because smaller patches are easier to review, and because interface part is more tricky and involves more issues ... Changes compared to original patch by J.H. * In J.H. patch if the feature is enabled, i.e. if $jslocaltime is not equal '' (the check should probably be if $jslocaltime is false-ish; neither '-0000' nor '+0000' is false-ish), five additional SCRIPT elements are added: four loading new external scripts (libraries), one running onloadTZSetup()... and not as window.onload handler. This series makes it so gitweb.js is composed of newly introduced or result of splitting JavaScript files, so $gitweb_js remains only loaded external script (note: it can be minified). onloadTZSetup call is added to anonymous function which is used as window.onload handler. Thus there are no new SCRIPT elements. * The default timezone is 'local' like in J.H. patch, but it is passed from gitweb.perl as onloadTZSetup argument, and not put in global variable tzDefault from gitweb variable $jslocaltime (sic!). Note that in this patch default timezone is not yet configurable, and that you cannot yet turn off this feature. * The cookie name is 'gitweb_tz' not 'tzOffset', and is passed from gitweb.perl as parameter to onloadTZSetup, and not put in global variable named getwebCookieTZOffset (sic!). * The classname that marks dates for manipulation by adjusting timezone is "datetime" and not "dtcommit" like in J.H. patch, because of taggerdate ('tag' view) case. It is passed to JavaScript code as argument to onloadTZSetup(). Note that thanks to next to previous patch we need to add '<span class="datetime">' only in one place: in format_timestamp_html function, as compared to J.H. patch modifying 3 places. * onloadTZSetup, which in this patch has options passed from gitweb by the way of function arguments rather than global variables, first checks cookie then fixes dates to given timezone; in J.H. patch it checks cookie last. In this patch we skip manipulating dates if timezone is 'utc', i.e. the same as gitweb already outputs. * original tzChangeNS -> tzChangeSNS (why this indirection?) finds elements by hardcoded classname "dtcommit" (though it might apply also to taggerdate), gets supposedly machine readable but not in all browsers (see Kevin comment in [1]) ISO-8601 format from title attribute, and uses it as base for datetime manipulation, and uses .innerHTML for changing output. fixDatetimeTZ finds elements with tzClassName class (passed down from call in gitweb.perl), uses original RFC-2822 formatted date from contents of the element (or rather its first child text node) as base for datetime manipulation, and uses .firstChild.data (W3C DOM 2 Core TextNode interface) for changing output. tzChangeSNS in J.H. patch also set cookie, and added triggers for timezone selection menu -- this really shouldn't be its job. The function to generate RFC-2822 date with adjusted timezone is named formatRFC2822Date and not dateOutputTZ. Please also take note of caching length of Array or live NodeSet in a loop. [1] http://thread.gmane.org/gmane.comp.version-control.git/169384/focus=169891 * The knowledge of "utc" and "local" timezones is encapsulated in normalizeTimezoneInfo() function in lib/datetime.js, instead of being in dateOutputTZ(). Knowledge about how to get local timezone in +/-HHMM format is contained in localTimezoneInfo() function. gitweb/Makefile | 1 + gitweb/gitweb.perl | 11 +++++-- gitweb/static/js/adjust-timezone.js | 60 +++++++++++++++++++++++++++++++++++ gitweb/static/js/lib/datetime.js | 15 +++++++++ 4 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 gitweb/static/js/adjust-timezone.js diff --git a/gitweb/Makefile b/gitweb/Makefile index 7dd1dee..5d20515 100644 --- a/gitweb/Makefile +++ b/gitweb/Makefile @@ -120,6 +120,7 @@ GITWEB_JSLIB_FILES += static/js/lib/common-lib.js GITWEB_JSLIB_FILES += static/js/lib/datetime.js GITWEB_JSLIB_FILES += static/js/lib/cookies.js GITWEB_JSLIB_FILES += static/js/javascript-detection.js +GITWEB_JSLIB_FILES += static/js/adjust-timezone.js GITWEB_JSLIB_FILES += static/js/blame_incremental.js diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 67bcfe8..6651946 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -3732,9 +3732,14 @@ sub git_footer_html { qq!startBlame("!. href(action=>"blame_data", -replay=>1) .qq!",\n!. qq! "!. href() .qq!");\n!. qq!</script>\n!; - } elsif (gitweb_check_feature('javascript-actions')) { + } else { print qq!<script type="text/javascript">\n!. - qq!window.onload = fixLinks;\n!. + qq!window.onload = function () {\n!. + (gitweb_check_feature('javascript-actions') ? + qq! fixLinks();\n! : ''). + # last parameter to onloadTZSetup must be CSS class used by format_timestamp_html + qq! onloadTZSetup('local', 'gitweb_tz', 'datetime');\n!. + qq!};\n!. qq!</script>\n!; } @@ -3940,7 +3945,7 @@ sub git_print_section { sub format_timestamp_html { my $date = shift; - my $strtime = $date->{'rfc2822'}; + my $strtime = '<span class="datetime">'.$date->{'rfc2822'}.'</span>'; my $localtime_format = '(%02d:%02d %s)'; if ($date->{'hour_local'} < 6) { diff --git a/gitweb/static/js/adjust-timezone.js b/gitweb/static/js/adjust-timezone.js new file mode 100644 index 0000000..1577d78 --- /dev/null +++ b/gitweb/static/js/adjust-timezone.js @@ -0,0 +1,60 @@ +// Copyright (C) 2011, John 'Warthog9' Hawley <warthog9@xxxxxxxxxxxxxx> +// 2011, Jakub Narebski <jnareb@xxxxxxxxx> + +/** + * @fileOverview Manipulate dates in gitweb output, adjusting timezone + * @license GPLv2 or later + */ + +/** + * Get common timezone and adjust dates to use this common timezone. + * + * This function is called during onload event (added to window.onload). + * + * @param {String} tzDefault: default timezone, if there is no cookie + * @param {String} tzCookieName: name of cookie to store timezone + * @param {String} tzClassName: denotes elements with date to be adjusted + */ +function onloadTZSetup(tzDefault, tzCookieName, tzClassName) { + var tzCookie = getCookie(tzCookieName); + var tz = tzCookie ? tzCookie : tzDefault; + + // server-side of gitweb produces datetime in UTC, + // so if tz is 'utc' there is no need for changes + if (tz !== 'utc') { + fixDatetimeTZ(tz, tzClassName); + } +} + + +/** + * Replace RFC-2822 dates contained in SPAN elements with tzClassName + * CSS class with equivalent dates in given timezone. + * + * @param {String} tz: numeric timezone in '(-|+)HHMM' format, or 'utc', or 'local' + * @param {String} tzClassName: specifies elements to be changed + */ +function fixDatetimeTZ(tz, tzClassName) { + // sanity check, method should be ensured by common-lib.js + if (!document.getElementsByClassName) { + return; + } + + // translate to timezone in '(-|+)HHMM' format + tz = normalizeTimezoneInfo(tz); + + // NOTE: result of getElementsByClassName should probably be cached + var classesFound = document.getElementsByClassName(tzClassName, "span"); + for (var i = 0, len = classesFound.length; i < len; i++) { + var curElement = classesFound[i]; + + // we use *.firstChild.data (W3C DOM) instead of *.innerHTML + // as the latter doesn't always work everywhere in every browser + var epoch = parseRFC2822Date(curElement.firstChild.data); + var adjusted = formatDateRFC2882(epoch, tz); + + curElement.firstChild.data = adjusted; + } +} + +/* end of adjust-timezone.js */ diff --git a/gitweb/static/js/lib/datetime.js b/gitweb/static/js/lib/datetime.js index b3dcedb..f78c60a 100644 --- a/gitweb/static/js/lib/datetime.js +++ b/gitweb/static/js/lib/datetime.js @@ -105,6 +105,21 @@ function formatTimezoneInfo(hours, minutes, sep) { } /** + * translate 'utc' and 'local' to numerical timezone + * @param {String} timezoneInfo: might be 'utc' or 'local' (browser) + */ +function normalizeTimezoneInfo(timezoneInfo) { + switch (timezoneInfo) { + case 'utc': + return '+0000'; + case 'local': // 'local' is browser timezone + return localTimezoneInfo(); + } + return timezoneInfo; +} + + +/** * return date in local time formatted in iso-8601 like format * 'yyyy-mm-dd HH:MM:SS +/-ZZZZ' e.g. '2005-08-07 21:49:46 +0200' * -- 1.7.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html