1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
# frozen_string_literal: true
require "zlib"
module Jekyll
class Avatar < Liquid::Tag
def self.generate_template_with(keys)
attrs = (BASE_ATTRIBUTES + keys).map! { |key| %(#{key}="%<#{key}>s") }.join(" ")
"<img #{attrs} />"
end
private_class_method :generate_template_with
#
SERVERS = 4
DEFAULT_SIZE = "40"
API_VERSION = "3"
BASE_ATTRIBUTES = %w(
class alt width height data-proofer-ignore src
).freeze
BASE_TEMPLATE = generate_template_with %w(srcset)
LAZY_TEMPLATE = generate_template_with %w(data-src data-srcset)
private_constant :BASE_ATTRIBUTES, :BASE_TEMPLATE, :LAZY_TEMPLATE
def initialize(_tag_name, text, _tokens)
super
@text = text.strip
@markup = Liquid::Template.parse(@text)
@size = compute_size
@user_variable = extract_user_variable
@custom_host = ENV["PAGES_AVATARS_URL"]
@custom_host = "" unless @custom_host.is_a?(String)
end
def render(context)
@context = context
@text = @markup.render(@context)
template = lazy_load? ? LAZY_TEMPLATE : BASE_TEMPLATE
format(template, attributes)
end
private
def attributes
result = {
:class => classes,
:alt => username,
:width => size,
:height => size,
:"data-proofer-ignore" => "true",
}
if lazy_load?
result[:src] = ""
result[:"data-src"] = url
result[:"data-srcset"] = srcset
else
result[:src] = url
result[:srcset] = srcset
end
result
end
def lazy_load?
@text.include?("lazy=true")
end
def extract_user_variable
matches = @text.match(%r!\buser=([\w.]+)\b!)
matches[1] if matches
end
def username
return lookup_variable(@user_variable) if @user_variable
result = @text.include?(" ") ? @text.split(" ")[0] : @text
result.start_with?("@") ? result.sub("@", "") : result
end
# Lookup a Liquid variable in the current context.
#
# variable - the variable name, as a string.
#
# Returns the value of the variable in the context or the variable name if not found.
def lookup_variable(variable)
lookup = @context
if variable.include?(".")
variable.split(".").each do |value|
lookup = lookup[value]
end
else
lookup = lookup[variable]
end
lookup || variable
end
# Returns a string value
def compute_size
matches = @text.match(%r!\bsize=(\d+)\b!i)
matches ? matches[1] : DEFAULT_SIZE
end
attr_reader :size
def path(scale = 1)
"#{username}?v=#{API_VERSION}&s=#{scale == 1 ? size : (size.to_i * scale)}"
end
def server_number
Zlib.crc32(path) % SERVERS
end
def host
if @custom_host.empty?
"https://avatars#{server_number}.githubusercontent.com"
else
@custom_host
end
end
def parsed_host
@parsed_host ||= {}
@parsed_host[host] ||= Addressable::URI.parse(host)
end
def url_with_custom_host(scale = 1)
uri = parsed_host
uri.path << "/" unless uri.path.end_with?("/")
uri = uri.join path(scale)
uri.to_s
end
def url(scale = 1)
return url_with_custom_host(scale) unless @custom_host.empty?
"#{host}/#{path(scale)}"
end
SCALES = %w(1 2 3 4).freeze
private_constant :SCALES
def srcset
SCALES.map { |scale| "#{url(scale.to_i)} #{scale}x" }.join(", ")
end
# See http://primercss.io/avatars/#small-avatars
def classes
size.to_i < 48 ? "avatar avatar-small" : "avatar"
end
end
end
Liquid::Template.register_tag("avatar", Jekyll::Avatar)
|