From 47d8f62efa9f7e145945a43ac74cd56032537ec8 Mon Sep 17 00:00:00 2001 From: NumEricR <-> Date: Sun, 24 Apr 2011 15:37:19 +0200 Subject: [PATCH 1/4] Add relative dates for user account creation --- js/githubresume.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/js/githubresume.js b/js/githubresume.js index 22a1a21..41178c1 100644 --- a/js/githubresume.js +++ b/js/githubresume.js @@ -65,6 +65,15 @@ var run = function() { var since = new Date(data.user.created_at); since = since.getFullYear(); + var currentYear = (new Date).getFullYear(); + switch (since) { + case currentYear-1: + since = 'last year'; + break; + case currentYear: + since = 'this year'; + break; + } var addHttp = ''; if (data.user.blog !== undefined && data.user.blog !== null) { From 7745780b79a6a95474187d3a670273d0eb65c379 Mon Sep 17 00:00:00 2001 From: NumEricR <-> Date: Sun, 24 Apr 2011 16:11:24 +0200 Subject: [PATCH 2/4] Don't show link with 0 repository on the profile part --- js/mustache.js | 270 +++++++++++++++++++++++++--------------------- views/resume.html | 2 +- 2 files changed, 149 insertions(+), 123 deletions(-) diff --git a/js/mustache.js b/js/mustache.js index 95a68d2..eb9c8c3 100644 --- a/js/mustache.js +++ b/js/mustache.js @@ -1,12 +1,7 @@ /* - Shameless port of http://github.com/defunkt/mustache - by Jan Lehnardt , - Alexander Lang , - Sebastian Cohnen +mustache.js — Logic-less templates in JavaScript - Thanks @defunkt for the awesome code. - - See http://github.com/defunkt/mustache for more info. +See http://mustache.github.com/ for more info. */ var Mustache = function() { @@ -17,11 +12,20 @@ var Mustache = function() { ctag: "}}", pragmas: {}, buffer: [], - pragmas_parsed: false, + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, render: function(template, context, partials, in_recursion) { + // reset buffer & set context + if(!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + // fail fast - if(template.indexOf(this.otag) == -1) { + if(!this.includes("", template)) { if(in_recursion) { return template; } else { @@ -30,13 +34,7 @@ var Mustache = function() { } } - if(!in_recursion) { - this.buffer = []; - } - - if(!this.pragmas_parsed) { - template = this.render_pragmas(template); - } + template = this.render_pragmas(template); var html = this.render_section(template, context, partials); if(in_recursion) { return this.render_tags(html, context, partials, in_recursion); @@ -46,8 +44,8 @@ var Mustache = function() { }, /* - Sends parsed lines - */ +Sends parsed lines +*/ send: function(line) { if(line != "") { this.buffer.push(line); @@ -55,19 +53,23 @@ var Mustache = function() { }, /* - Looks for %PRAGMAS - */ +Looks for %PRAGMAS +*/ render_pragmas: function(template) { - this.pragmas_parsed = true; // no pragmas - if(template.indexOf(this.otag + "%") == -1) { + if(!this.includes("%", template)) { return template; } var that = this; - var regex = new RegExp(this.otag + "%([\\w_-]+) ?([\\w]+=[\\w]+)?" - + this.ctag); + var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + + this.ctag); return template.replace(regex, function(match, pragma, options) { + if(!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } that.pragmas[pragma] = {}; if(options) { var opts = options.split("="); @@ -79,85 +81,106 @@ var Mustache = function() { }, /* - Tries to find a partial in the global scope and render it - */ +Tries to find a partial in the curent scope and render it +*/ render_partial: function(name, context, partials) { - if(typeof(context[name]) != "object") { - throw({message: "subcontext for '" + name + "' is not an object"}); - } - if(!partials || !partials[name]) { + name = this.trim(name); + if(!partials || partials[name] === undefined) { throw({message: "unknown_partial '" + name + "'"}); } + if(typeof(context[name]) != "object") { + return this.render(partials[name], context, partials, true); + } return this.render(partials[name], context[name], partials, true); }, /* - Renders boolean and enumerable sections - */ +Renders inverted (^) and normal (#) sections +*/ render_section: function(template, context, partials) { - if(template.indexOf(this.otag + "#") == -1) { + if(!this.includes("#", template) && !this.includes("^", template)) { return template; } + var that = this; // CSW - Added "+?" so it finds the tighest bound, not the widest - var regex = new RegExp(this.otag + "\\#(.+)" + this.ctag + - "\\s*([\\s\\S]+?)" + this.otag + "\\/\\1" + this.ctag + "\\s*", "mg"); + var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag + + "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag + + "\\s*", "mg"); // for each {{#foo}}{{/foo}} section do... - return template.replace(regex, function(match, name, content) { + return template.replace(regex, function(match, type, name, content) { var value = that.find(name, context); - if(that.is_array(value)) { // Enumerable, Let's loop! - return that.map(value, function(row) { - return that.render(content, that.merge(context, - that.create_context(row)), partials, true); - }).join(""); - } else if(value) { // boolean section - return that.render(content, context, partials, true); - } else { - return ""; + if(type == "^") { // inverted section + if(!value || that.is_array(value) && value.length === 0) { + // false or empty list, render it + return that.render(content, context, partials, true); + } else { + return ""; + } + } else if(type == "#") { // normal section + if(that.is_array(value)) { // Enumerable, Let's loop! + return that.map(value, function(row) { + return that.render(content, that.create_context(row), + partials, true); + }).join(""); + } else if(that.is_object(value)) { // Object, Use it as subcontext! + return that.render(content, that.create_context(value), + partials, true); + } else if(typeof value === "function") { + // higher order section + return value.call(context, content, function(text) { + return that.render(text, context, partials, true); + }); + } else if(value) { // boolean section + return that.render(content, context, partials, true); + } else { + return ""; + } } }); }, /* - Replace {{foo}} and friends with values from our view - */ +Replace {{foo}} and friends with values from our view +*/ render_tags: function(template, context, partials, in_recursion) { // tit for tat var that = this; var new_regex = function() { - return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\/#]+?)\\1?" + + return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + that.ctag + "+", "g"); }; var regex = new_regex(); + var tag_replace_callback = function(match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + return that.find(name, context); + default: // escape the value + return that.escape(that.find(name, context)); + } + }; var lines = template.split("\n"); - for (var i=0; i < lines.length; i++) { - lines[i] = lines[i].replace(regex, function(match, operator, name) { - switch(operator) { - case "!": // ignore comments - return match; - case "=": // set new delimiters, rebuild the replace regexp - that.set_delimiters(name); - regex = new_regex(); - return ""; - case ">": // render partial - return that.render_partial(name, context, partials); - case "{": // the triple mustache is unescaped - return that.find(name, context); - default: // escape the value - return that.escape(that.find(name, context)); - } - }, this); - if(!in_recursion) { - this.send(lines[i]); - } - } + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if(!in_recursion) { + this.send(lines[i]); + } + } - if(in_recursion) { - return lines.join("\n"); - } + if(in_recursion) { + return lines.join("\n"); + } }, set_delimiters: function(delimiters) { @@ -177,20 +200,33 @@ var Mustache = function() { '(\\' + specials.join('|\\') + ')', 'g' ); } - return text.replace(arguments.callee.sRE, '\\$1'); + return text.replace(arguments.callee.sRE, '\\$1'); }, /* - find `name` in current `context`. That is find me a value - from the view object - */ +find `name` in current `context`. That is find me a value +from the view object +*/ find: function(name, context) { name = this.trim(name); - if(typeof context[name] === "function") { - return context[name].apply(context); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; } - if(context[name] !== undefined) { - return context[name]; + + var value; + if(is_kinda_truthy(context[name])) { + value = context[name]; + } else if(is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + + if(typeof value === "function") { + return value.apply(context); + } + if(value !== undefined) { + return value; } // silently ignore unkown variables return ""; @@ -198,49 +234,39 @@ var Mustache = function() { // Utility methods - /* - Does away with nasty characters - */ - escape: function(s) { - return ((s == null) ? "" : s).toString().replace(/[&"<>\\]/g, function(s) { - switch(s) { - case "&": return "&"; - case "\\": return "\\\\";; - case '"': return '\"';; - case "<": return "<"; - case ">": return ">"; - default: return s; - } - }); + /* includes tag */ + includes: function(needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; }, /* - Merges all properties of object `b` into object `a`. - `b.property` overwrites a.property` - */ - merge: function(a, b) { - var _new = {}; - for(var name in a) { - if(a.hasOwnProperty(name)) { - _new[name] = a[name]; +Does away with nasty characters +*/ + escape: function(s) { + s = String(s === null ? "" : s); + return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) { + switch(s) { + case "&": return "&"; + case "\\": return "\\\\"; + case '"': return '\"'; + case "<": return "<"; + case ">": return ">"; + default: return s; } - }; - for(var name in b) { - if(b.hasOwnProperty(name)) { - _new[name] = b[name]; - } - }; - return _new; + }); }, // by @langalex, support for arrays of strings create_context: function(_context) { if(this.is_object(_context)) { return _context; - } else if(this.pragmas["IMPLICIT-ITERATOR"]) { - var iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator || "."; + } else { + var iterator = "."; + if(this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } var ctx = {}; - ctx[iterator] = _context + ctx[iterator] = _context; return ctx; } }, @@ -254,22 +280,22 @@ var Mustache = function() { }, /* - Gets rid of leading and trailing whitespace - */ +Gets rid of leading and trailing whitespace +*/ trim: function(s) { return s.replace(/^\s*|\s*$/g, ""); }, /* - Why, why, why? Because IE. Cry, cry cry. - */ +Why, why, why? Because IE. Cry, cry cry. +*/ map: function(array, fn) { if (typeof array.map == "function") { - return array.map(fn) + return array.map(fn); } else { var r = []; var l = array.length; - for(i=0;i{{repos}} public {{plural}}. + {{#repos}}with {{repos}} public {{plural}}{{/repos}}{{^repos}}without any public repository for now{{/repos}}. I've been using github.com since {{since}} {{#blog}} and sometimes I blog at {{blog}}. From 951807b5f0de23bdc842ffdf6d796f11629f8762 Mon Sep 17 00:00:00 2001 From: NumEricR <-> Date: Sun, 24 Apr 2011 16:54:38 +0200 Subject: [PATCH 3/4] Add "early adopter" mention for user accounts created on first months of Github --- js/githubresume.js | 11 +++++++++-- views/resume.html | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/js/githubresume.js b/js/githubresume.js index 41178c1..ea8535b 100644 --- a/js/githubresume.js +++ b/js/githubresume.js @@ -63,8 +63,9 @@ var run = function() { repos = data; }); - var since = new Date(data.user.created_at); - since = since.getFullYear(); + var sinceDate = new Date(data.user.created_at); + since = sinceDate.getFullYear(); + var sinceMonth = sinceDate.getMonth(); var currentYear = (new Date).getFullYear(); switch (since) { case currentYear-1: @@ -91,6 +92,7 @@ var run = function() { name: name, email: data.user.email, created_at: data.user.created_at, + earlyAdopter: 0, location: data.user.location, gravatar_id: data.user.gravatar_id, repos: data.user.public_repo_count, @@ -103,6 +105,11 @@ var run = function() { view.blog = addHttp + data.user.blog; } + // We consider a limit of 4 months since the Github opening (Feb 2008) to be considered as an early adopter + if (since == '2008' && sinceMonth <= 5) { + view.earlyAdopter = 1; + } + $.ajax({ url: 'views/resume.html', dataType: 'html', diff --git a/views/resume.html b/views/resume.html index c7df071..8df4c79 100644 --- a/views/resume.html +++ b/views/resume.html @@ -36,7 +36,7 @@ based in {{location}} {{/location}} {{#repos}}with {{repos}} public {{plural}}{{/repos}}{{^repos}}without any public repository for now{{/repos}}. - I've been using github.com since {{since}} + I've been using github.com since {{since}}{{#earlyAdopter}}, therefore I'm an early adopter,{{/earlyAdopter}} {{#blog}} and sometimes I blog at {{blog}}. {{/blog}} From c19167bccd05fe416464488d48d8d70e8d0fae01 Mon Sep 17 00:00:00 2001 From: NumEricR Date: Tue, 4 Sep 2012 23:41:41 +0200 Subject: [PATCH 4/4] Fix format of GitHub wordings --- js/githubresume.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/js/githubresume.js b/js/githubresume.js index e905476..d5dec89 100644 --- a/js/githubresume.js +++ b/js/githubresume.js @@ -122,12 +122,12 @@ var run = function() { followers: data.followers, followersLabel: data.followers > 1 ? 'followers' : 'follower', username: username, - userStatus: 'Github user', + userStatus: 'GitHub user', since: since, resume_url: window.location }; - // We consider a limit of 4 months since the Github opening (Feb 2008) to be considered as an early adopter + // We consider a limit of 4 months since the GitHub opening (Feb 2008) to be considered as an early adopter if (since == '2008' && sinceMonth <= 5) { view.earlyAdopter = 1; } @@ -161,22 +161,22 @@ var run = function() { } if (statusScore == FIRST_STEP) { - return 'Inactive Github user'; + return 'Inactive GitHub user'; } else if (statusScore > FIRST_STEP && statusScore <= SECOND_STEP) { - return 'Newbie Github user'; + return 'Newbie GitHub user'; } else if (statusScore > SECOND_STEP && statusScore <= THIRD_STEP) { - return 'Regular Github user'; + return 'Regular GitHub user'; } else if (statusScore > THIRD_STEP && statusScore <= FOURTH_STEP) { - return 'Advanced Github user'; + return 'Advanced GitHub user'; } else if (statusScore > FOURTH_STEP && statusScore <= FIFTH_STEP) { - return 'Enthusiastic Github user'; + return 'Enthusiastic GitHub user'; } else if (statusScore > FIFTH_STEP) { - return 'Passionate Github user'; + return 'Passionate GitHub user'; } };