]>
Lady’s Gitweb - Gitweb/blob - static/js/adjust-timezone.js
1 // Copyright (C) 2011, John 'Warthog9' Hawley <warthog9@eaglescrag.net>
2 // 2011, Jakub Narebski <jnareb@gmail.com>
5 * @fileOverview Manipulate dates in gitweb output, adjusting timezone
6 * @license GPLv2 or later
10 * Get common timezone, add UI for changing timezones, and adjust
11 * dates to use requested common timezone.
13 * This function is called during onload event (added to window.onload).
15 * @param {String} tzDefault: default timezone, if there is no cookie
16 * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone
17 * @param {String} tzCookieInfo.name: name of cookie to store timezone
18 * @param {String} tzClassName: denotes elements with date to be adjusted
20 function onloadTZSetup(tzDefault
, tzCookieInfo
, tzClassName
) {
21 var tzCookieTZ
= getCookie(tzCookieInfo
.name
, tzCookieInfo
);
25 // set timezone to value saved in a cookie
27 // refresh cookie, so its expiration counts from last use of gitweb
28 setCookie(tzCookieInfo
.name
, tzCookieTZ
, tzCookieInfo
);
31 // add UI for changing timezone
32 addChangeTZ(tz
, tzCookieInfo
, tzClassName
);
34 // server-side of gitweb produces datetime in UTC,
35 // so if tz is 'utc' there is no need for changes
36 var nochange
= tz
=== 'utc';
38 // adjust dates to use specified common timezone
39 fixDatetimeTZ(tz
, tzClassName
, nochange
);
43 /* ...................................................................... */
44 /* Changing dates to use requested timezone */
47 * Replace RFC-2822 dates contained in SPAN elements with tzClassName
48 * CSS class with equivalent dates in given timezone.
50 * @param {String} tz: numeric timezone in '(-|+)HHMM' format, or 'utc', or 'local'
51 * @param {String} tzClassName: specifies elements to be changed
52 * @param {Boolean} nochange: markup for timezone change, but don't change it
54 function fixDatetimeTZ(tz
, tzClassName
, nochange
) {
55 // sanity check, method should be ensured by common-lib.js
56 if (!document
.getElementsByClassName
) {
60 // translate to timezone in '(-|+)HHMM' format
61 tz
= normalizeTimezoneInfo(tz
);
63 // NOTE: result of getElementsByClassName should probably be cached
64 var classesFound
= document
.getElementsByClassName(tzClassName
, "span");
65 for (var i
= 0, len
= classesFound
.length
; i
< len
; i
++) {
66 var curElement
= classesFound
[i
];
68 curElement
.title
= 'Click to change timezone';
70 // we use *.firstChild.data (W3C DOM) instead of *.innerHTML
71 // as the latter doesn't always work everywhere in every browser
72 var epoch
= parseRFC2822Date(curElement
.firstChild
.data
);
73 var adjusted
= formatDateRFC2882(epoch
, tz
);
75 curElement
.firstChild
.data
= adjusted
;
81 /* ...................................................................... */
82 /* Adding triggers, generating timezone menu, displaying and hiding */
85 * Adds triggers for UI to change common timezone used for dates in
86 * gitweb output: it marks up and/or creates item to click to invoke
87 * timezone change UI, creates timezone UI fragment to be attached,
88 * and installs appropriate onclick trigger (via event delegation).
90 * @param {String} tzSelected: pre-selected timezone,
91 * 'utc' or 'local' or '(-|+)HHMM'
92 * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone
93 * @param {String} tzClassName: specifies elements to install trigger
95 function addChangeTZ(tzSelected
, tzCookieInfo
, tzClassName
) {
96 // make link to timezone UI discoverable
97 addCssRule('.'+tzClassName
+ ':hover',
98 'text-decoration: underline; cursor: help;');
100 // create form for selecting timezone (to be saved in a cookie)
101 var tzSelectFragment
= document
.createDocumentFragment();
102 tzSelectFragment
= createChangeTZForm(tzSelectFragment
,
103 tzSelected
, tzCookieInfo
, tzClassName
);
105 // event delegation handler for timezone selection UI (clicking on entry)
106 // see http://www.nczonline.net/blog/2009/06/30/event-delegation-in-javascript/
107 // assumes that there is no existing document.onclick handler
108 document
.onclick
= function onclickHandler(event
) {
109 //IE doesn't pass in the event object
110 event
= event
|| window
.event
;
112 //IE uses srcElement as the target
113 var target
= event
.target
|| event
.srcElement
;
115 switch (target
.className
) {
117 // don't display timezone menu if it is already displayed
118 if (tzSelectFragment
.childNodes
.length
> 0) {
119 displayChangeTZForm(target
, tzSelectFragment
);
127 * Create DocumentFragment with UI for changing common timezone in
128 * which dates are shown in.
130 * @param {DocumentFragment} documentFragment: where attach UI
131 * @param {String} tzSelected: default (pre-selected) timezone
132 * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone
133 * @returns {DocumentFragment}
135 function createChangeTZForm(documentFragment
, tzSelected
, tzCookieInfo
, tzClassName
) {
136 var div
= document
.createElement("div");
137 div
.className
= 'popup';
139 /* '<div class="close-button" title="(click on this box to close)">X</div>' */
140 var closeButton
= document
.createElement('div');
141 closeButton
.className
= 'close-button';
142 closeButton
.title
= '(click on this box to close)';
143 closeButton
.appendChild(document
.createTextNode('X'));
144 closeButton
.onclick
= closeTZFormHandler(documentFragment
, tzClassName
);
145 div
.appendChild(closeButton
);
147 /* 'Select timezone: <br clear="all">' */
148 div
.appendChild(document
.createTextNode('Select timezone: '));
149 var br
= document
.createElement('br');
153 /* '<select name="tzoffset">
155 * <option value="-0700">UTC-07:00</option>
156 * <option value="-0600">UTC-06:00</option>
159 var select
= document
.createElement("select");
160 select
.name
= "tzoffset";
161 //select.style.clear = 'all';
162 select
.appendChild(generateTZOptions(tzSelected
));
163 select
.onchange
= selectTZHandler(documentFragment
, tzCookieInfo
, tzClassName
);
164 div
.appendChild(select
);
166 documentFragment
.appendChild(div
);
168 return documentFragment
;
173 * Hide (remove from DOM) timezone change UI, ensuring that it is not
174 * garbage collected and that it can be re-enabled later.
176 * @param {DocumentFragment} documentFragment: contains detached UI
177 * @param {HTMLSelectElement} target: select element inside of UI
178 * @param {String} tzClassName: specifies element where UI was installed
179 * @returns {DocumentFragment} documentFragment
181 function removeChangeTZForm(documentFragment
, target
, tzClassName
) {
182 // find containing element, where we appended timezone selection UI
183 // `target' is somewhere inside timezone menu
184 var container
= target
.parentNode
, popup
= target
;
186 container
.className
!== tzClassName
) {
188 container
= container
.parentNode
;
190 // safety check if we found correct container,
191 // and if it isn't deleted already
192 if (!container
|| !popup
||
193 container
.className
!== tzClassName
||
194 popup
.className
!== 'popup') {
195 return documentFragment
;
198 // timezone selection UI was appended as last child
199 // see also displayChangeTZForm function
200 var removed
= popup
.parentNode
.removeChild(popup
);
201 if (documentFragment
.firstChild
!== removed
) { // the only child
202 // re-append it so it would be available for next time
203 documentFragment
.appendChild(removed
);
205 // all of inline style was added by this script
206 // it is not really needed to remove it, but it is a good practice
207 container
.removeAttribute('style');
209 return documentFragment
;
214 * Display UI for changing common timezone for dates in gitweb output.
215 * To be used from 'onclick' event handler.
217 * @param {HTMLElement} target: where to install/display UI
218 * @param {DocumentFragment} tzSelectFragment: timezone selection UI
220 function displayChangeTZForm(target
, tzSelectFragment
) {
221 // for absolute positioning to be related to target element
222 target
.style
.position
= 'relative';
223 target
.style
.display
= 'inline-block';
225 // show/display UI for changing timezone
226 target
.appendChild(tzSelectFragment
);
230 /* ...................................................................... */
231 /* List of timezones for timezone selection menu */
234 * Generate list of timezones for creating timezone select UI
236 * @returns {Object[]} list of e.g. { value: '+0100', descr: 'GMT+01:00' }
238 function generateTZList() {
240 { value: "utc", descr: "UTC/GMT"},
241 { value: "local", descr: "Local (per browser)"}
244 // generate all full hour timezones (no fractional timezones)
245 for (var x
= -12, idx
= timezones
.length
; x
<= +14; x
++, idx
++) {
246 var hours
= (x
>= 0 ? '+' : '-') + padLeft(x
>=0 ? x : -x
, 2);
247 timezones
[idx
] = { value: hours
+ '00', descr: 'UTC' + hours
+ ':00'};
249 timezones
[idx
].descr
= 'UTC\u00B100:00'; // 'UTC±00:00'
257 * Generate <options> elements for timezone select UI
259 * @param {String} tzSelected: default timezone
260 * @returns {DocumentFragment} list of options elements to appendChild
262 function generateTZOptions(tzSelected
) {
263 var elems
= document
.createDocumentFragment();
264 var timezones
= generateTZList();
266 for (var i
= 0, len
= timezones
.length
; i
< len
; i
++) {
267 var tzone
= timezones
[i
];
268 var option
= document
.createElement("option");
269 if (tzone
.value
=== tzSelected
) {
270 option
.defaultSelected
= true;
272 option
.value
= tzone
.value
;
273 option
.appendChild(document
.createTextNode(tzone
.descr
));
275 elems
.appendChild(option
);
282 /* ...................................................................... */
283 /* Event handlers and/or their generators */
286 * Create event handler that select timezone and closes timezone select UI.
287 * To be used as $('select[name="tzselect"]').onchange handler.
289 * @param {DocumentFragment} tzSelectFragment: timezone selection UI
290 * @param {Object} tzCookieInfo: object literal with info about cookie to store timezone
291 * @param {String} tzCookieInfo.name: name of cookie to save result of selection
292 * @param {String} tzClassName: specifies element where UI was installed
293 * @returns {Function} event handler
295 function selectTZHandler(tzSelectFragment
, tzCookieInfo
, tzClassName
) {
296 //return function selectTZ(event) {
297 return function (event
) {
298 event
= event
|| window
.event
;
299 var target
= event
.target
|| event
.srcElement
;
301 var selected
= target
.options
.item(target
.selectedIndex
);
302 removeChangeTZForm(tzSelectFragment
, target
, tzClassName
);
305 selected
.defaultSelected
= true;
306 setCookie(tzCookieInfo
.name
, selected
.value
, tzCookieInfo
);
307 fixDatetimeTZ(selected
.value
, tzClassName
);
313 * Create event handler that closes timezone select UI.
314 * To be used e.g. as $('.closebutton').onclick handler.
316 * @param {DocumentFragment} tzSelectFragment: timezone selection UI
317 * @param {String} tzClassName: specifies element where UI was installed
318 * @returns {Function} event handler
320 function closeTZFormHandler(tzSelectFragment
, tzClassName
) {
321 //return function closeTZForm(event) {
322 return function (event
) {
323 event
= event
|| window
.event
;
324 var target
= event
.target
|| event
.srcElement
;
326 removeChangeTZForm(tzSelectFragment
, target
, tzClassName
);
330 /* end of adjust-timezone.js */
This page took 0.67173 seconds and 5 git commands to generate.