',
75 | '
',
76 | '
',
77 | '
',
78 | '
',
79 | 'Github Finder',
80 | '',
81 | '',
86 | '',
87 | 'Loading...',
88 | '
',
89 | '
', // .p
90 | '
', // #r_w
91 |
92 | '
', // #repo info wrapper
93 | '
',
94 | '
',
95 |
96 | '
', // browser wrapper
97 | '
',
98 | '
',
99 |
100 | '
', // info_wrapper
101 | '
Info
',
102 | '
Select an item or navigate with arrow keys
',
103 | '
',
104 |
105 | // '
',
106 | '
', // #finder
107 |
108 | '
', // file content wrapper
109 | '
', // file header
110 | '
',
113 | '
',
114 |
115 | '
', // file content
116 | '
', // padding
117 | '
', // file wrapper
118 | '
', // file
119 | '
',
120 | '
',
121 | '
', // padding
122 | '
',
123 |
124 | '
', // commit wrapper
125 | '
',
126 | '
Commits Log
',
127 | '
Commits Log
', // commits log wrapper
128 | '
',
129 | '
',
130 | '
', // #c_w
131 |
132 | '
',
133 | '
', // #f_c_w
134 |
135 | '' // # content
141 | ].join(' ');
142 | }
143 |
144 | /* openRepo */
145 | ,oR: function(repo) {
146 | this.reset()
147 |
148 | var u,r,b;
149 | if( !repo ) {
150 | /* check URL params */
151 | var p = uP();
152 | if( p["user_id"] && p["repo"] ) {
153 | u = this.u = p["user_id"];
154 | r = this.r = p["repo"]
155 | b = this.b = p["branch"] || 'master';
156 | } else {
157 | // debugger
158 | /* if user just come from a github repo ... */
159 | var m = (new RegExp("^https?://github.com/(.+)","i")).exec(document.referrer),
160 | path = m ? m[1].split('/') : [];
161 |
162 | if( path[0] && path[1] ) {
163 | u = this.u = path[0];
164 | r = this.r = path[1];
165 | b = this.b = path[3] || 'master';
166 | } else { /* default to app settings */
167 | u = this.u;
168 | r = this.r;
169 | b = this.b;
170 | }
171 | }
172 | } else {
173 | /* User hits the "Go" button: grabbing the user/repo */
174 | repo = repo.split('/');
175 | if( repo.length < 2 ) { alert('invalid repository!'); return; }
176 |
177 | u = this.u = repo[0];
178 | r = this.r = repo[1];
179 | b = this.b = ($('brs') ? $F('brs') : b) || 'master';
180 | }
181 |
182 |
183 | $('r').value = u + '/' + r;
184 |
185 | /* Load the master branch */
186 | GH.Commits.listBranch( u, r, b, {
187 | onData: function(cs) {
188 | // if(!cs.commits) { alert('repo not found'); return; }
189 | var tree_sha = cs.commits[0].tree;
190 | this.renderPanel(tree_sha);
191 | }.bind(this)
192 | });
193 |
194 | /* Show the repo info */
195 | GH.Repo.show( u, r, {
196 | onData: function(repo) {
197 | this.repo = repo;
198 | this.renderRepoInfo();
199 | }.bind(this)
200 | });
201 |
202 | /* Show branches info */
203 | GH.Repo.listBranches( u, r, {
204 | onData: function(bes) {
205 | this.bes = $H(bes);
206 | this.rBs();
207 | }.bind(this)
208 | });
209 |
210 | }
211 |
212 | ,reset: function() {
213 | $('f_c_w').hide();
214 | this.cI = -1;
215 | this.pI = 0;
216 |
217 | while(this.ps.length > 0)
218 | (this.ps.pop()).dispose();
219 | }
220 |
221 | ,browse: function() {
222 | if( _gaq ) _gaq.push(["_trackEvent", "browse repo", "go", $F('r') ] );
223 |
224 | $('i').innerHTML = '';
225 | this.oR( $F('r') || $('r').readAttribute('placeholder') );
226 |
227 | return false;
228 | }
229 | /* render the status bar */
230 | ,renderRepoInfo: function() {
231 | $('r_i').innerHTML = this.repo.description;
232 | }
233 |
234 | /* render branches */
235 | ,rBs: function() {
236 | var h = '
');
244 | $('brs_w').innerHTML = h + '';
245 | }
246 |
247 | ,renderPanel: function( sh, ix, it ) {
248 | ix = ix || 0;
249 | /* clear previously opened panels */
250 | for( var i = this.ps.length - 1; i > ix; i-- ) {
251 | (this.ps.pop()).dispose();
252 | }
253 | this.open( sh, it );
254 | }
255 |
256 | ,_resizePanelsWrapper: function() {
257 | var w = (this.ps.length * 201);
258 | this.psW.style.width = w + 'px';
259 |
260 | /* scroll to the last panel */
261 | this.bW.scrollLeft = w;
262 | }
263 |
264 | /* request the content of the tree and render the panel */
265 | ,open: function( tree_sha, item ) {
266 | GH.Tree.show( this.u, this.r, this.b, tree_sha, {
267 | onData: function(tree) { // tree is already sorted
268 | /* add all items to cache */
269 | for( var i = 0, len = tree.length; i < len; i++ )
270 | this.shas[ tree[i].sha ] = tree[i];
271 |
272 | var name = item ? item.name : '' ;
273 | // debugger
274 | var p = new P( this, { tree: tree, index: this.ps.length, name: name, tree_sha: tree_sha, item: item } );
275 | this.ps.push( p );
276 |
277 | this._resizePanelsWrapper();
278 |
279 | }.bind(this)
280 | });
281 | }
282 |
283 | /**
284 | * @sha: the sha of the object
285 | * @e: the source element
286 | * @kb: is this trigged by the keyboard
287 | */
288 | ,click: function(sha, e, kb) {
289 | // console.log("kb" + kb);
290 | // debugger
291 | var it = this.shas[ sha ],
292 | ix = +(e.up('.panel')).readAttribute('data-index'),
293 | path = "";
294 |
295 |
296 | /* set selection cursor && focus the item */
297 | e.up('ul').select('li.cur').invoke('removeClassName','cur');
298 | var p = e.up('div.panel'),
299 | li = e.up('li').addClassName('cur'),
300 | posTop = li.positionedOffset().top + li.offsetHeight - p.offsetHeight;
301 | if( posTop > p.scrollTop) {
302 | p.scrollTop = posTop ;
303 | }
304 |
305 | /* current index */
306 | this.cI = it.index;
307 | this.pI = ix; // current panel index;
308 |
309 | /* remember the current selected item */
310 | this.ps[ ix ].cI = it.index;
311 |
312 |
313 | /* don't be trigger happy: ptm = preview timer */
314 | if(this._p) clearTimeout( this._p );
315 |
316 | /* set a small delay here incase user switches really fast (e.g. keyboard navigation ) */
317 | this._p = setTimeout( function(){
318 |
319 | if( it.type == 'tree' ) {
320 | this.renderPanel( it.sha, ix, it );
321 | // don't show file preview panel
322 | $('f_c_w').hide();
323 | } else {
324 |
325 | $('f_c_w').show();
326 | // console.log("it %o", JSON.stringify(it));
327 |
328 | if( /text|javascript|application\/x-/.test(it.mime_type) ) {
329 | $('f').innerHTML = '
Loading File';
330 | GH.Blob.show( this.u, this.r, it.sha, { onSuccess: function(r) {
331 | this.previewTextFile(r.responseText, it);
332 | }.bind(this)} );
333 | }
334 | }
335 |
336 |
337 | /* display file info */
338 | for( var i = 0; i <= ix; i++ )
339 | path += this.ps[i].name + "/";
340 | path += it.name;
341 |
342 |
343 | var c, cs;
344 | var info = function() {
345 | var h = [
346 | '
',
353 | '
',
354 | '
Path
' + path + '
',
355 |
356 | '
',
357 | '
Last Committed
' +
358 | s( c.id ) +
359 | ( Prototype.Browser.IE ? '' : ' on ' + (new Date(c.committed_date)).toString() ) +
360 | '
',
361 | '
',
362 |
363 | '
',
368 | '
',
369 | '
',
370 | 'Commit Message
',
371 | c.message,
372 | '
'
373 | ];
374 | $('i').update( h.join(''));
375 | }.bind(this);
376 |
377 | /* showPreview */
378 | var p = function() {
379 | $('diffoutput').hide();
380 | $('f_c_w').show();
381 | $('f_h').innerHTML = path;
382 | }
383 |
384 | /* commits log */
385 | var cl = function() {
386 | var dW, dH, dP,
387 | csHTML = '
';
388 | // debugger
389 | var dl = function(a,b,l) { // difflink a, b, label
390 | // google event tracking to track the diff usage
391 | var eventTracker = '_gaq.push(["_trackEvent", "commits log", "diff", "' + l + '"]);';
392 | return '
' + l + ' ';
395 | };
396 |
397 | /* to get an object at a commit: need the commit id, then path
398 | then it's just
399 | http://github.com/:user_id/:repo/blob/:commit_id/:path
400 | */
401 |
402 | for( var i = 0; i < cs.length; i++ ) {
403 | dW = cs.length > 1 ? '
Diff with: ' : ''; // diffWith
404 | dH = i > 0 ? dl( c , cs[i], 'Head') : '' ; // diffHead
405 | dP = cs[i+1] ? dl(cs[i], cs[i+1], 'Previous') : '' ; // diffPrevious
406 |
407 | csHTML +=
408 | '
' +
409 | '' + s(cs[i].id) +'' + ' by ' + cs[i].author.name +
410 | dW + dH + (dH && dP ? ' - ' : '') + dP +
411 | '
';
412 | };
413 | // csHTML.push('
');
414 | $('c_l_w').update( csHTML + '
' );
415 | };
416 |
417 | /* query the cs to get a list of cs and info */
418 | GH.Commits.list( this.u, this.r, this.b, path, { onData: function(cms) { // cms == commits
419 | it.c = c = cms[0]; // also assign the it's c to keep track of folder's latest commit
420 | cs = cms;
421 |
422 | info();
423 |
424 | if( it.type != 'tree' ) {
425 | p();
426 | cl();
427 | }
428 |
429 | }.bind(this)});
430 | }.bind(this), (kb ? 350 : 10)); // time out
431 |
432 |
433 | }
434 |
435 |
436 | ,previewTextFile: function( text, it ) {
437 | text = text.replace(/\r\n/, "\n").split(/\n/);
438 |
439 | var ln = [],
440 | l = [],
441 | sloc = 0;
442 | for( var i = 0, len = text.length; i < len; i++ ) {
443 | ln.push( '
' + (i + 1) + "\n");
444 |
445 | l.push( text[i] ? text[i].replace(/&/g, '&').replace(/',
452 | '
' + it.mode + '',
453 | '
' + text.length + ' lines (' + sloc +' sloc)',
454 | '
' + it.size + ' bytes',
455 | '
Theme: ',
459 | '
',
460 |
461 | '