Skip to content

Commit

Permalink
gitweb: Split JavaScript for maintability, combining on build
Browse files Browse the repository at this point in the history
Split originally single gitweb.js file into smaller files, each
dealing with single issue / area of responsibility.  This move should
make gitweb's JavaScript code easier to maintain.

For better webapp performance it is recommended[1][2][3] to combine
JavaScript files.  Do it during build time (in gitweb/Makefile), by
straight concatenation of files into gitweb.js file (which is now
ignored as being generated).  This means that there are no changes to
gitweb script itself - it still uses gitweb.js or gitweb.min.js, but
now generated.

[1]: http://developer.yahoo.com/performance/rules.html
     "Minimize HTTP Requests" section
[2]: http://code.google.com/speed/articles/include-scripts-properly.html
     "1. Combine external JavaScript files"
[3]: http://javascript-reference.info/speed-up-your-javascript-load-time.htm
     "Combine Your Files" section.

See also new gitweb/static/js/README file.

Inspired-by-patch-by: John 'Warthog9' Hawley <warthog9@eaglescrag.net>
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jakub Narebski authored and Junio C Hamano committed May 24, 2011
1 parent f09f1d3 commit 9a86dd5
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 206 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
/gitk-git/gitk-wish
/gitweb/GITWEB-BUILD-OPTIONS
/gitweb/gitweb.cgi
/gitweb/static/gitweb.js
/gitweb/static/gitweb.min.*
/test-chmtime
/test-ctype
Expand Down
16 changes: 15 additions & 1 deletion gitweb/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ ifndef V
endif
endif

all:: gitweb.cgi
all:: gitweb.cgi static/gitweb.js

GITWEB_PROGRAMS = gitweb.cgi

Expand All @@ -112,6 +112,15 @@ endif

GITWEB_FILES += static/git-logo.png static/git-favicon.png

# JavaScript files that are composed (concatenated) to form gitweb.js
#
# js/lib/common-lib.js should be always first, then js/lib/*.js,
# then the rest of files; js/gitweb.js should be last (if it exists)
GITWEB_JSLIB_FILES += static/js/lib/common-lib.js
GITWEB_JSLIB_FILES += static/js/javascript-detection.js
GITWEB_JSLIB_FILES += static/js/blame_incremental.js


GITWEB_REPLACE = \
-e 's|++GIT_VERSION++|$(GIT_VERSION)|g' \
-e 's|++GIT_BINDIR++|$(bindir)|g' \
Expand Down Expand Up @@ -146,6 +155,11 @@ gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS
chmod +x $@+ && \
mv $@+ $@

static/gitweb.js: $(GITWEB_JSLIB_FILES)
$(QUIET_GEN)$(RM) $@ $@+ && \
cat $^ >$@+ && \
mv $@+ $@

### Testing rules

test:
Expand Down
20 changes: 20 additions & 0 deletions gitweb/static/js/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
GIT web interface (gitweb) - JavaScript
=======================================

This directory holds JavaScript code used by gitweb (GIT web interface).
Scripts from there would be concatenated together in the order specified
by gitweb/Makefile into gitweb/static/gitweb.js, during building of
gitweb/gitweb.cgi (during gitweb building). The resulting file (or its
minification) would then be installed / deployed together with gitweb.

Scripts in 'lib/' subdirectory compose generic JavaScript library,
providing features required by gitweb but in no way limited to gitweb
only. In the future those scripts could be replaced by some JavaScript
library / framework, like e.g. jQuery, YUI, Prototype, MooTools, Dojo,
ExtJS, Script.aculo.us or SproutCore.

All scripts that manipulate gitweb output should be put outside 'lib/',
directly in this directory ('gitweb/static/js/'). Those scripts would
have to be rewritten if gitweb moves to using some JavaScript library.

See also comments in gitweb/Makefile.
208 changes: 3 additions & 205 deletions gitweb/static/gitweb.js → gitweb/static/js/blame_incremental.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,12 @@
// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com>
// 2007, Petr Baudis <pasky@suse.cz>
// 2008-2009, Jakub Narebski <jnareb@gmail.com>
// 2008-2011, Jakub Narebski <jnareb@gmail.com>

/**
* @fileOverview JavaScript code for gitweb (git web interface).
* @fileOverview JavaScript side of Ajax-y 'blame_incremental' view in gitweb
* @license GPLv2 or later
*/

/* ============================================================ */
/* functions for generic gitweb actions and views */

/**
* used to check if link has 'js' query parameter already (at end),
* and other reasons to not add 'js=1' param at the end of link
* @constant
*/
var jsExceptionsRe = /[;?]js=[01]$/;

/**
* Add '?js=1' or ';js=1' to the end of every link in the document
* that doesn't have 'js' query parameter set already.
*
* Links with 'js=1' lead to JavaScript version of given action, if it
* exists (currently there is only 'blame_incremental' for 'blame')
*
* @globals jsExceptionsRe
*/
function fixLinks() {
var allLinks = document.getElementsByTagName("a") || document.links;
for (var i = 0, len = allLinks.length; i < len; i++) {
var link = allLinks[i];
if (!jsExceptionsRe.test(link)) { // =~ /[;?]js=[01]$/;
link.href +=
(link.href.indexOf('?') === -1 ? '?' : ';') + 'js=1';
}
}
}


/* ============================================================ */

/*
* This code uses DOM methods instead of (nonstandard) innerHTML
Expand All @@ -58,71 +26,6 @@ function fixLinks() {
*/


/* ============================================================ */
/* generic utility functions */


/**
* pad number N with nonbreakable spaces on the left, to WIDTH characters
* example: padLeftStr(12, 3, '\u00A0') == '\u00A012'
* ('\u00A0' is nonbreakable space)
*
* @param {Number|String} input: number to pad
* @param {Number} width: visible width of output
* @param {String} str: string to prefix to string, e.g. '\u00A0'
* @returns {String} INPUT prefixed with (WIDTH - INPUT.length) x STR
*/
function padLeftStr(input, width, str) {
var prefix = '';

width -= input.toString().length;
while (width > 0) {
prefix += str;
width--;
}
return prefix + input;
}

/**
* Pad INPUT on the left to SIZE width, using given padding character CH,
* for example padLeft('a', 3, '_') is '__a'.
*
* @param {String} input: input value converted to string.
* @param {Number} width: desired length of output.
* @param {String} ch: single character to prefix to string.
*
* @returns {String} Modified string, at least SIZE length.
*/
function padLeft(input, width, ch) {
var s = input + "";
while (s.length < width) {
s = ch + s;
}
return s;
}

/**
* Create XMLHttpRequest object in cross-browser way
* @returns XMLHttpRequest object, or null
*/
function createRequestObject() {
try {
return new XMLHttpRequest();
} catch (e) {}
try {
return window.createRequest();
} catch (e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {}
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}

return null;
}


/* ============================================================ */
/* utility/helper functions (and variables) */

Expand Down Expand Up @@ -392,111 +295,6 @@ function fixColorsAndGroups() {
}
}

/* ............................................................ */
/* time and data */

/**
* used to extract hours and minutes from timezone info, e.g '-0900'
* @constant
*/
var tzRe = /^([+-])([0-9][0-9])([0-9][0-9])$/;

/**
* convert numeric timezone +/-ZZZZ to offset from UTC in seconds
*
* @param {String} timezoneInfo: numeric timezone '(+|-)HHMM'
* @returns {Number} offset from UTC in seconds for timezone
*
* @globals tzRe
*/
function timezoneOffset(timezoneInfo) {
var match = tzRe.exec(timezoneInfo);
var tz_sign = (match[1] === '-' ? -1 : +1);
var tz_hour = parseInt(match[2],10);
var tz_min = parseInt(match[3],10);

return tz_sign*(((tz_hour*60) + tz_min)*60);
}

/**
* 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'
*
* @param {Number} epoch: seconds since '00:00:00 1970-01-01 UTC'
* @param {String} timezoneInfo: numeric timezone '(+|-)HHMM'
* @returns {String} date in local time in iso-8601 like format
*/
function formatDateISOLocal(epoch, timezoneInfo) {
// date corrected by timezone
var localDate = new Date(1000 * (epoch +
timezoneOffset(timezoneInfo)));
var localDateStr = // e.g. '2005-08-07'
localDate.getUTCFullYear() + '-' +
padLeft(localDate.getUTCMonth()+1, 2, '0') + '-' +
padLeft(localDate.getUTCDate(), 2, '0');
var localTimeStr = // e.g. '21:49:46'
padLeft(localDate.getUTCHours(), 2, '0') + ':' +
padLeft(localDate.getUTCMinutes(), 2, '0') + ':' +
padLeft(localDate.getUTCSeconds(), 2, '0');

return localDateStr + ' ' + localTimeStr + ' ' + timezoneInfo;
}

/* ............................................................ */
/* unquoting/unescaping filenames */

/**#@+
* @constant
*/
var escCodeRe = /\\([^0-7]|[0-7]{1,3})/g;
var octEscRe = /^[0-7]{1,3}$/;
var maybeQuotedRe = /^\"(.*)\"$/;
/**#@-*/

/**
* unquote maybe git-quoted filename
* e.g. 'aa' -> 'aa', '"a\ta"' -> 'a a'
*
* @param {String} str: git-quoted string
* @returns {String} Unquoted and unescaped string
*
* @globals escCodeRe, octEscRe, maybeQuotedRe
*/
function unquote(str) {
function unq(seq) {
var es = {
// character escape codes, aka escape sequences (from C)
// replacements are to some extent JavaScript specific
t: "\t", // tab (HT, TAB)
n: "\n", // newline (NL)
r: "\r", // return (CR)
f: "\f", // form feed (FF)
b: "\b", // backspace (BS)
a: "\x07", // alarm (bell) (BEL)
e: "\x1B", // escape (ESC)
v: "\v" // vertical tab (VT)
};

if (seq.search(octEscRe) !== -1) {
// octal char sequence
return String.fromCharCode(parseInt(seq, 8));
} else if (seq in es) {
// C escape sequence, aka character escape code
return es[seq];
}
// quoted ordinary character
return seq;
}

var match = str.match(maybeQuotedRe);
if (match) {
str = match[1];
// perhaps str = eval('"'+str+'"'); would be enough?
str = str.replace(escCodeRe,
function (substr, p1, offset, s) { return unq(p1); });
}
return str;
}

/* ============================================================ */
/* main part: parsing response */
Expand Down Expand Up @@ -886,4 +684,4 @@ function startBlame(blamedataUrl, bUrl) {
pollTimer = setInterval(xhr.onreadystatechange, 1000);
}

// end of gitweb.js
/* end of blame_incremental.js */
43 changes: 43 additions & 0 deletions gitweb/static/js/javascript-detection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com>
// 2007, Petr Baudis <pasky@suse.cz>
// 2008-2011, Jakub Narebski <jnareb@gmail.com>

/**
* @fileOverview Detect if JavaScript is enabled, and pass it to server-side
* @license GPLv2 or later
*/


/* ============================================================ */
/* Manipulating links */

/**
* used to check if link has 'js' query parameter already (at end),
* and other reasons to not add 'js=1' param at the end of link
* @constant
*/
var jsExceptionsRe = /[;?]js=[01]$/;

/**
* Add '?js=1' or ';js=1' to the end of every link in the document
* that doesn't have 'js' query parameter set already.
*
* Links with 'js=1' lead to JavaScript version of given action, if it
* exists (currently there is only 'blame_incremental' for 'blame')
*
* To be used as `window.onload` handler
*
* @globals jsExceptionsRe
*/
function fixLinks() {
var allLinks = document.getElementsByTagName("a") || document.links;
for (var i = 0, len = allLinks.length; i < len; i++) {
var link = allLinks[i];
if (!jsExceptionsRe.test(link)) { // =~ /[;?]js=[01]$/;
link.href +=
(link.href.indexOf('?') === -1 ? '?' : ';') + 'js=1';
}
}
}

/* end of javascript-detection.js */
Loading

0 comments on commit 9a86dd5

Please sign in to comment.