Permalink
Browse files

Add --user-icons option: none, gravatar, and identicon.

  • Loading branch information...
dekimsey committed Nov 7, 2012
1 parent c8f6848 commit ee8ec78da76e3773246b4e144b637ef1f3420e80
View
@@ -73,6 +73,10 @@ opts = OptionParser.new do |opts|
wiki_options[:mathjax] = true
end
+ opts.on("--user-icons [SOURCE]", "Set the history user icons. Valid values: gravatar, identicon, none. Default: none.") do
+ wiki_options[:user_icons] = source
+ end
+
opts.on("--show-all", "Shows all files in file view. By default only valid pages are shown.") do
wiki_options[:show_all] = true
end
View
@@ -69,6 +69,7 @@ Gem::Specification.new do |s|
lib/gollum/frontend/public/gollum/css/gollum.css
lib/gollum/frontend/public/gollum/css/ie7.css
lib/gollum/frontend/public/gollum/css/template.css
+ lib/gollum/frontend/public/gollum/images/man_24.png
lib/gollum/frontend/public/gollum/images/dirty-shade.png
lib/gollum/frontend/public/gollum/images/fileview/document.png
lib/gollum/frontend/public/gollum/images/fileview/folder-horizontal.png
@@ -91,6 +92,7 @@ Gem::Specification.new do |s|
lib/gollum/frontend/public/gollum/javascript/gollum.dialog.js
lib/gollum/frontend/public/gollum/javascript/gollum.js
lib/gollum/frontend/public/gollum/javascript/gollum.placeholder.js
+ lib/gollum/frontend/public/gollum/javascript/identicon_canvas.js
lib/gollum/frontend/public/gollum/javascript/jquery-1.7.2.min.js
lib/gollum/frontend/public/gollum/javascript/jquery.color.js
lib/gollum/frontend/public/gollum/javascript/mousetrap.min.js
@@ -443,6 +445,9 @@ Gem::Specification.new do |s|
lib/gollum/frontend/templates/pages.mustache
lib/gollum/frontend/templates/search.mustache
lib/gollum/frontend/templates/searchbar.mustache
+ lib/gollum/frontend/templates/history_authors/gravatar.mustache
+ lib/gollum/frontend/templates/history_authors/identicon.mustache
+ lib/gollum/frontend/templates/history_authors/none.mustache
lib/gollum/frontend/uri_encode_component.rb
lib/gollum/frontend/views/compare.rb
lib/gollum/frontend/views/create.rb
View
@@ -1,6 +1,7 @@
# ~*~ encoding: utf-8 ~*~
# stdlib
require 'digest/md5'
+require 'digest/sha1'
require 'ostruct'
# external
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -228,4 +228,21 @@ $(document).ready(function() {
});
$.GollumEditor({ NewFile: true, MarkupType: default_markup });
}
+
+ if( $('#wiki-history').length ){
+ var lookup = {};
+ $('img.identicon').each(function(index, element){
+ var $item = $(element);
+ var code = parseInt($item.data('identicon'), 10);
+ var img_bin = lookup[code];
+ if( img_bin === undefined ){
+ var size = 16;
+ var canvas = $('<canvas width=16 height=16/>').get(0);
+ render_identicon(canvas, code, 16);
+ img_bin = canvas.toDataURL("image/png");
+ lookup[code] = img_bin;
+ }
+ $item.attr('src', img_bin);
+ });
+ }
});
@@ -0,0 +1,111 @@
+/*
+Client-side Canvas tag based Identicon rendering code
+
+@author Don Park
+@version 0.2
+@date January 21th, 2007
+*/
+
+var patch0 = new Array( 0, 4, 24, 20 );
+var patch1 = new Array( 0, 4, 20 );
+var patch2 = new Array( 2, 24, 20 );
+var patch3 = new Array( 0, 2, 20, 22 );
+var patch4 = new Array( 2, 14, 22, 10 );
+var patch5 = new Array( 0, 14, 24, 22 );
+var patch6 = new Array( 2, 24, 22, 13, 11, 22, 20 );
+var patch7 = new Array( 0, 14, 22 );
+var patch8 = new Array( 6, 8, 18, 16 );
+var patch9 = new Array( 4, 20, 10, 12, 2 );
+var patch10 = new Array( 0, 2, 12, 10 );
+var patch11 = new Array( 10, 14, 22 );
+var patch12 = new Array( 20, 12, 24 );
+var patch13 = new Array( 10, 2, 12 );
+var patch14 = new Array( 0, 2, 10 );
+var patchTypes = new Array( patch0, patch1, patch2, patch3, patch4,
+ patch5, patch6, patch7, patch8, patch9, patch10, patch11,
+ patch12, patch13, patch14, patch0 );
+var centerPatchTypes = new Array(0, 4, 8, 15);
+
+function render_identicon_patch(ctx, x, y, size, patch, turn, invert, foreColor, backColor) {
+ patch %= patchTypes.length;
+ turn %= 4;
+ if (patch == 15)
+ invert = !invert;
+
+ var vertices = patchTypes[patch];
+ var offset = size / 2;
+ var scale = size / 4;
+
+ ctx.save();
+
+ // paint background
+ ctx.fillStyle = invert ? foreColor : backColor;
+ ctx.fillRect(x, y, size, size);
+
+ // build patch path
+ ctx.translate(x + offset, y + offset);
+ ctx.rotate(turn * Math.PI / 2);
+ ctx.beginPath();
+ ctx.moveTo((vertices[0] % 5 * scale - offset), (Math.floor(vertices[0] / 5) * scale - offset));
+ for (var i = 1; i < vertices.length; i++)
+ ctx.lineTo((vertices[i] % 5 * scale - offset), (Math.floor(vertices[i] / 5) * scale - offset));
+ ctx.closePath();
+
+ // offset and rotate coordinate space by patch position (x, y) and
+ // 'turn' before rendering patch shape
+
+ // render rotated patch using fore color (back color if inverted)
+ ctx.fillStyle = invert ? backColor : foreColor;
+ ctx.fill();
+
+ // restore rotation
+ ctx.restore();
+}
+
+function render_identicon(node, code, size) {
+ if (!node || !code || !size) return;
+
+ var patchSize = size / 3;
+ var middleType = centerPatchTypes[code & 3];
+ var middleInvert = ((code >> 2) & 1) != 0;
+ var cornerType = (code >> 3) & 15;
+ var cornerInvert = ((code >> 7) & 1) != 0;
+ var cornerTurn = (code >> 8) & 3;
+ var sideType = (code >> 10) & 15;
+ var sideInvert = ((code >> 14) & 1) != 0;
+ var sideTurn = (code >> 15) & 3;
+ var blue = (code >> 16) & 31;
+ var green = (code >> 21) & 31;
+ var red = (code >> 27) & 31;
+ var foreColor = "rgb(" + (red << 3) + "," + (green << 3) + "," + (blue << 3) + ")";
+ var backColor = "rgb(255,255,255)";
+
+ var ctx = node.getContext("2d");
+
+ // middle patch
+ render_identicon_patch(ctx, patchSize, patchSize, patchSize, middleType, 0, middleInvert, foreColor, backColor);
+ // side patchs, starting from top and moving clock-wise
+ render_identicon_patch(ctx, patchSize, 0, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
+ render_identicon_patch(ctx, patchSize * 2, patchSize, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
+ render_identicon_patch(ctx, patchSize, patchSize * 2, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
+ render_identicon_patch(ctx, 0, patchSize, patchSize, sideType, sideTurn++, sideInvert, foreColor, backColor);
+ // corner patchs, starting from top left and moving clock-wise
+ render_identicon_patch(ctx, 0, 0, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
+ render_identicon_patch(ctx, patchSize * 2, 0, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
+ render_identicon_patch(ctx, patchSize * 2, patchSize * 2, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
+ render_identicon_patch(ctx, 0, patchSize * 2, patchSize, cornerType, cornerTurn++, cornerInvert, foreColor, backColor);
+}
+
+function render_identicon_canvases(prefix) {
+ var canvases = document.getElementsByTagName("canvas");
+ var n = canvases.length;
+ for (var i = 0; i < n; i++) {
+ var node = canvases[i];
+ if (node.title && node.title.indexOf(prefix) == 0) {
+ if (node.style.display == 'none') node.style.display = "inline";
+ var code = node.title.substring(prefix.length) * 1;
+ var size = node.width;
+ render_identicon(node, code, size);
+ }
+ }
+}
@@ -30,11 +30,7 @@
<input type="checkbox" name="versions[]" value="{{id}}">
</td>
<td class="author">
- <a href="javascript:void(0)">
- <img src="https://secure.gravatar.com/avatar/{{gravatar}}?s=16"
- alt="avatar: {{author}}" class="mini-gravatar">
- <span class="username">{{author}}</span>
- </a>
+ {{>author_template}}
</td>
<td class="commit-name">
<span class="time-elapsed">{{date}}:</span>&nbsp;
@@ -0,0 +1,5 @@
+<a href="javascript:void(0)">
+<img src="https://secure.gravatar.com/avatar/{{gravatar}}?s=16"
+ alt="avatar: {{author}}" class="mini-gravatar"/>
+ <span class="username">{{author}}</span>
+</a>
@@ -0,0 +1,5 @@
+<a href="javascript:void(0)">
+ <img src="{{base_url}}/images/man_24.png" alt="avatar: {{author}}"
+ class="mini-gravatar identicon" data-identicon="{{identicon}}"/>
+ <span class="username">{{author}}</span>
+</a>
@@ -0,0 +1,3 @@
+<a href="javascript:void(0)">
+ <span class="username">{{author}}</span>
+</a>
@@ -19,6 +19,9 @@
<script type="text/javascript" src="{{base_url}}/javascript/gollum.dialog.js"></script>
<script type="text/javascript" src="{{base_url}}/javascript/gollum.placeholder.js"></script>
<script type="text/javascript" src="{{base_url}}/javascript/editor/gollum.editor.js"></script>
+ {{#use_identicon}}
+ <script type="text/javascript" src="{{base_url}}/javascript/identicon_canvas.js"></script>
+ {{/use_identicon}}
{{#mathjax}}
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
@@ -20,7 +20,30 @@ def versions
:author => v.author.name.respond_to?(:force_encoding) ? v.author.name.force_encoding('UTF-8') : v.author.name,
:message => v.message.respond_to?(:force_encoding) ? v.message.force_encoding('UTF-8') : v.message,
:date => v.authored_date.strftime("%B %d, %Y"),
- :gravatar => Digest::MD5.hexdigest(v.author.email) }
+ :gravatar => Digest::MD5.hexdigest(v.author.email),
+ :identicon => self._identicon_code(v.author.email),
+ }
+ end
+ end
+
+ def _identicon_code(blob)
+ sha_bytes = Digest::SHA1.hexdigest(blob + @request.host)[0,20]
+ # Thanks donpark's IdenticonUtil.java for this.
+ return ((sha_bytes[0] & 0xFF) << 24) |
+ ((sha_bytes[1] & 0xFF) << 16) |
+ ((sha_bytes[2] & 0xFF) << 8) |
+ (sha_bytes[3] & 0xFF)
+ end
+
+ def use_identicon
+ @page.wiki.user_icons == 'identicon'
+ end
+
+ def partial(name)
+ if name == :author_template
+ self.class.partial("history_authors/#{@page.wiki.user_icons}")
+ else
+ super
end
end
@@ -93,6 +93,10 @@ def css # custom css
@css
end
+ def use_identicon
+ @page.wiki.user_icons == 'identicon'
+ end
+
# Access to embedded metadata.
#
# Examples
View
@@ -163,6 +163,8 @@ def history_sanitization
# :ref - String the repository ref to retrieve pages from
# :ws_subs - Array of chars to sub for ws in filenames.
# :mathjax - Set to false to disable mathjax.
+ # :user_icons - Enable user icons on the history page. [gravatar, identicon, none].
+ # Default: none
# :show_all - Show all files in file view, not just valid pages.
# Default: false
# :collapse_tree - Start with collapsed file view. Default: false
@@ -201,6 +203,7 @@ def initialize(path, options = {})
@collapse_tree = options.fetch :collapse_tree, false
@css = options.fetch :css, false
@h1_title = options.fetch :h1_title, false
+ @user_icons = options.fetch :user_icons, 'none'
end
# Public: check whether the wiki's git repo exists on the filesystem.
@@ -609,6 +612,9 @@ def history_sanitizer
# Toggles mathjax.
attr_reader :mathjax
+ # Toggles user icons. Default: 'gravatar'
+ attr_reader :user_icons
+
# Toggles showing all files in files view. Default is false.
# When false, only valid pages in the git repo are displayed.
attr_reader :show_all
View
@@ -30,3 +30,23 @@ http://www.thecssninja.com/css/css-tree-menu
http://www.thecssninja.com/demo/license.txt
lib/gollum/frontend/public/css/_styles.css
+
+---
+
+Default profile image (man_24.png) is used under the CC BY-SA 3.0 Unported license.
+
+CC BY-SA 3.0 Unported
+http://blog.twg.ca/2010/11/retina-display-icon-set/
+http://creativecommons.org/licenses/by-sa/3.0/legalcode.txt
+
+ lib/gollum/frontend/public/images/man_24.png
+
+---
+
+The canvas_identicon code is used under the MIT license.
+
+https://github.com/donpark/identicon/blob/master/identicon-canvas/identicon_canvas.js
+https://github.com/donpark/identicon/blob/master/README
+
+ lib/gollum/frontend/public/gollum/javascript/identicon_canvas.js
+

0 comments on commit ee8ec78

Please sign in to comment.