ginatra 3.0.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -15
- data/.travis.yml +7 -6
- data/CONTRIBUTING.md +30 -0
- data/Gemfile +1 -9
- data/LICENSE.txt +30 -0
- data/README.md +63 -114
- data/Rakefile +10 -12
- data/bin/ginatra +79 -63
- data/config.ru +35 -3
- data/ginatra.gemspec +29 -18
- data/lib/ginatra.rb +161 -148
- data/lib/ginatra/config.rb +18 -121
- data/lib/ginatra/errors.rb +10 -0
- data/lib/ginatra/helpers.rb +154 -139
- data/lib/ginatra/repo.rb +67 -82
- data/lib/ginatra/repo_list.rb +25 -18
- data/lib/ginatra/repo_stats.rb +93 -0
- data/lib/ginatra/version.rb +4 -0
- data/lib/git/webby.rb +292 -0
- data/lib/git/webby/extensions.rb +10 -0
- data/lib/git/webby/http_backend.rb +177 -0
- data/lib/sinatra/partials.rb +1 -1
- data/public/css/application.css +6 -0
- data/public/css/custom.css +57 -0
- data/public/css/lib/bootstrap-responsive.min.css +9 -0
- data/public/css/lib/bootstrap.min.css +9 -0
- data/public/css/lib/highlight.css +209 -0
- data/public/img/glyphicons-halflings-white.png +0 -0
- data/public/img/glyphicons-halflings.png +0 -0
- data/public/img/spin.gif +0 -0
- data/public/js/application.js +5 -0
- data/public/js/custom.js +51 -0
- data/public/js/lib/bootstrap.min.js +6 -0
- data/public/js/lib/jquery.lazyload.min.js +2 -0
- data/public/js/lib/jquery.min.js +2 -0
- data/public/js/lib/jquery.pjax.js +739 -0
- data/repos/README.md +21 -8
- data/spec/ginatra/helpers_spec.rb +95 -0
- data/spec/ginatra/repo_list_spec.rb +66 -0
- data/spec/ginatra/repo_spec.rb +78 -0
- data/spec/ginatra/repo_stats_spec.rb +27 -0
- data/spec/ginatra_spec.rb +121 -0
- data/spec/spec_helper.rb +8 -17
- data/views/404.erb +18 -0
- data/views/500.erb +18 -0
- data/views/_footer.erb +7 -0
- data/views/_header.erb +12 -6
- data/views/_tree_nav.erb +53 -0
- data/views/atom.erb +32 -0
- data/views/blob.erb +27 -8
- data/views/commit.erb +95 -17
- data/views/empty_repo.erb +10 -0
- data/views/index.erb +27 -11
- data/views/layout.erb +16 -20
- data/views/log.erb +74 -54
- data/views/stats.erb +89 -0
- data/views/tree.erb +32 -20
- metadata +168 -94
- data/bin/ginatra-daemon +0 -87
- data/bin/ginatra-directory +0 -55
- data/bin/ginatra-server +0 -27
- data/bin/ginatra-setup +0 -28
- data/lib/ginatra/graph_commit.rb +0 -77
- data/public/img/add.png +0 -0
- data/public/img/diff.png +0 -0
- data/public/img/doc.png +0 -0
- data/public/img/rm.png +0 -0
- data/public/img/tree.png +0 -0
- data/public/src/branch-graph.js +0 -170
- data/public/src/colour.css +0 -86
- data/public/src/commit.css +0 -211
- data/public/src/ginatra.js +0 -7
- data/public/src/github.css +0 -129
- data/public/src/graph.css +0 -9
- data/public/src/highlight.pack.js +0 -1
- data/public/src/index.css +0 -92
- data/public/src/lists.css +0 -25
- data/public/src/raphael.js +0 -7
- data/public/src/reset.css +0 -49
- data/public/src/table.css +0 -33
- data/public/src/type.css +0 -30
- data/rackup.ru +0 -5
- data/spec/graph_commit_spec.rb +0 -54
- data/spec/repo_list_spec.rb +0 -84
- data/spec/repo_spec.rb +0 -61
- data/views/_actor_box.erb +0 -13
- data/views/_commit_info_box.erb +0 -27
- data/views/_tree_part.erb +0 -11
- data/views/atom.builder +0 -32
- data/views/graph.erb +0 -15
data/lib/ginatra/config.rb
CHANGED
@@ -1,130 +1,27 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require "logger"
|
1
|
+
require 'yaml'
|
2
|
+
require 'ostruct'
|
4
3
|
|
5
4
|
module Ginatra
|
5
|
+
def self.config
|
6
|
+
@config ||= OpenStruct.new load_config
|
7
|
+
end
|
6
8
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
current_path
|
13
|
-
|
14
|
-
|
15
|
-
CONFIG_PATH = File.expand_path("~/.ginatra/config.yml")
|
16
|
-
|
17
|
-
# A default config that we fall back to if no file is found.
|
18
|
-
DEFAULT_CONFIG = {
|
19
|
-
:git_dirs => [File.expand_path("#{current_path}/../../repos/*")],
|
20
|
-
:ignored_files => ['README.md'],
|
21
|
-
:description => "View My Git Repositories",
|
22
|
-
:port => 9797,
|
23
|
-
:host => "0.0.0.0",
|
24
|
-
:prefix => "/"
|
25
|
-
}
|
26
|
-
|
27
|
-
def self.logger
|
28
|
-
return @logger if @logger
|
29
|
-
|
30
|
-
log_file = Ginatra::Config[:log_file] || STDOUT
|
31
|
-
|
32
|
-
# create log_file location
|
33
|
-
# The log_file config option should be an absolute file system path
|
34
|
-
# It doesn't have to exist, but ginatra should have the proper file system privileges to create the directories
|
35
|
-
# and files along the specified path
|
36
|
-
unless log_file == STDOUT
|
37
|
-
parent_dir, separator, file_component = log_file.rpartition("/")
|
38
|
-
FileUtils.mkdir_p parent_dir
|
39
|
-
FileUtils.touch log_file
|
40
|
-
end
|
41
|
-
|
42
|
-
# determine log level from config file
|
43
|
-
# The log_level config option should be one of the Logger::Severity constant names (case doesn't matter)
|
44
|
-
# example: :log_level: debug
|
45
|
-
log_level = Ginatra::Config[:log_level]
|
46
|
-
|
47
|
-
if log_level.nil?
|
48
|
-
log_level = Logger::WARN
|
49
|
-
else
|
50
|
-
log_level = Logger.const_get(log_level.to_s.upcase.to_sym)
|
51
|
-
log_level = Logger::WARN if log_level.nil?
|
52
|
-
end
|
53
|
-
|
54
|
-
@logger = Logger.new(log_file)
|
55
|
-
@logger.level = log_level
|
56
|
-
@logger.formatter = Proc.new {|s, t, n, msg| "[#{t}] #{msg}\n"}
|
57
|
-
@logger
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.safe_setup
|
61
|
-
unless File.exist?(CONFIG_PATH)
|
62
|
-
FileUtils.mkdir_p(File.dirname(CONFIG_PATH))
|
63
|
-
File.open(CONFIG_PATH, 'w') do |f|
|
64
|
-
YAML.dump(DEFAULT_CONFIG, f)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Loads the configuration and merges it with
|
70
|
-
# the default configuration.
|
71
|
-
#
|
72
|
-
# @return [Hash] config a hash of the configuration options
|
73
|
-
def self.load!
|
74
|
-
loaded_config = {}
|
75
|
-
@config = DEFAULT_CONFIG.dup
|
76
|
-
if File.size(CONFIG_PATH) == 0
|
77
|
-
dump!
|
78
|
-
else
|
79
|
-
loaded_config = YAML.load_file(CONFIG_PATH)
|
80
|
-
@config.merge!(loaded_config)
|
81
|
-
end
|
82
|
-
@config
|
83
|
-
end
|
84
|
-
|
85
|
-
# Dumps the _current_ configuration to +CONFIG_PATH+
|
86
|
-
# again WITHOUT regard for what's already there.
|
87
|
-
#
|
88
|
-
# Very Destructive Method. Use with care!
|
89
|
-
def self.dump!
|
90
|
-
File.open(CONFIG_PATH, 'w') do |f|
|
91
|
-
YAML.dump(@config, f)
|
92
|
-
end
|
93
|
-
end
|
9
|
+
# Loads the configuration and merges it with
|
10
|
+
# custom configuration if necessary.
|
11
|
+
#
|
12
|
+
# @return [Hash] config a hash of the configuration options
|
13
|
+
def self.load_config
|
14
|
+
current_path = File.expand_path(File.dirname(__FILE__))
|
15
|
+
custom_config_file = File.expand_path("~/.ginatra/config.yml")
|
16
|
+
default_config_file = File.expand_path("#{current_path}/../../config.yml")
|
94
17
|
|
95
|
-
|
96
|
-
#
|
97
|
-
# The first is respond to any hash methods
|
98
|
-
# and execute them on the +@config+ hash.
|
99
|
-
#
|
100
|
-
# The second is to do something like
|
101
|
-
# +Ginatra::Config.port+ instead of something
|
102
|
-
# like +Ginatra::Config[:port]+
|
103
|
-
#
|
104
|
-
# @return depends on what's in the config hash.
|
105
|
-
def self.method_missing(sym, *args, &block)
|
106
|
-
if @config.respond_to?(sym)
|
107
|
-
@config.send(sym, *args, &block)
|
108
|
-
elsif @config.has_key?(sym)
|
109
|
-
@config[sym]
|
110
|
-
else
|
111
|
-
super
|
112
|
-
end
|
113
|
-
end
|
18
|
+
config = YAML.load_file(default_config_file)
|
114
19
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# @see Ginatra::Config.method_missing
|
119
|
-
def self.respond_to?(name)
|
120
|
-
if @config.respond_to?(name)
|
121
|
-
true
|
122
|
-
elsif @config.has_key?(name)
|
123
|
-
true
|
124
|
-
else
|
125
|
-
super
|
126
|
-
end
|
20
|
+
if File.exist?(custom_config_file)
|
21
|
+
custom_config = YAML.load_file(custom_config_file)
|
22
|
+
config.merge!(custom_config)
|
127
23
|
end
|
128
24
|
|
25
|
+
config
|
129
26
|
end
|
130
27
|
end
|
data/lib/ginatra/helpers.rb
CHANGED
@@ -1,30 +1,89 @@
|
|
1
|
-
require
|
1
|
+
require 'digest/md5'
|
2
2
|
|
3
3
|
module Ginatra
|
4
|
-
# Helpers used in the views
|
5
|
-
# but not exclusively.
|
4
|
+
# Helpers used in the views, and not only.
|
6
5
|
module Helpers
|
6
|
+
# Escapes string to HTML entities
|
7
|
+
def h(text)
|
8
|
+
Rack::Utils.escape_html(text)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Checks X-PJAX header
|
12
|
+
def is_pjax?
|
13
|
+
request.env['HTTP_X_PJAX']
|
14
|
+
end
|
7
15
|
|
8
|
-
#
|
9
|
-
def
|
10
|
-
|
16
|
+
# Sets title for pages
|
17
|
+
def title(*args)
|
18
|
+
@title ||= []
|
19
|
+
@title_options ||= { headline: nil, sitename: nil }
|
20
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
11
21
|
|
12
|
-
|
22
|
+
@title += args
|
23
|
+
@title_options.merge!(options)
|
24
|
+
|
25
|
+
t = @title.clone
|
26
|
+
t << @title_options[:headline]
|
27
|
+
t << @title_options[:sitename]
|
28
|
+
t.compact.join ' - '
|
29
|
+
end
|
30
|
+
|
31
|
+
# Constructs the URL used in the layout's base tag
|
32
|
+
def prefix_url(rest_of_url='')
|
33
|
+
prefix = Ginatra.config.prefix.to_s
|
34
|
+
|
35
|
+
if prefix.length > 0 && prefix[-1].chr == '/'
|
13
36
|
prefix.chop!
|
14
37
|
end
|
15
38
|
|
16
39
|
"#{prefix}/#{rest_of_url}"
|
17
40
|
end
|
18
41
|
|
19
|
-
#
|
42
|
+
# Returns hint to set repository description
|
43
|
+
def empty_description_hint_for(repo)
|
44
|
+
return '' unless repo.description.empty?
|
45
|
+
hint_text = "Edit `#{repo.path}description` file to set the repository description."
|
46
|
+
"<span class='icon-exclamation-sign' title='#{hint_text}'></span>"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns file icon depending on filemode
|
50
|
+
def file_icon(filemode)
|
51
|
+
case filemode
|
52
|
+
# symbolic link (120000)
|
53
|
+
when 40960 then "<span class='icon-share-alt'></span>"
|
54
|
+
# executable file (100755)
|
55
|
+
when 33261 then "<span class='icon-asterisk'></span>"
|
56
|
+
else "<span class='icon-file'></span>"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Masks original email
|
61
|
+
def secure_mail(email)
|
62
|
+
local, domain = email.split('@')
|
63
|
+
"#{local[0..3]}...@#{domain}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Takes an email and returns an image tag with gravatar
|
20
67
|
#
|
21
68
|
# @param [String] email the email address
|
22
|
-
# @
|
23
|
-
|
24
|
-
|
69
|
+
# @param [Hash] options alt, class and size options for image tag
|
70
|
+
# @return [String] html image tag
|
71
|
+
def gravatar_image_tag(email, options={})
|
72
|
+
alt = options.fetch(:alt, email.gsub(/@\S*/, ''))
|
73
|
+
size = options.fetch(:size, 40)
|
74
|
+
url = "https://secure.gravatar.com/avatar/#{Digest::MD5.hexdigest(email)}?s=#{size}"
|
75
|
+
|
76
|
+
if options[:lazy]
|
77
|
+
placeholder = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
78
|
+
tag = "<img data-original='#{url}' src='#{placeholder}' alt='#{h alt}' height='#{size}' width='#{size}' class='js-lazy #{options[:class]}'>"
|
79
|
+
else
|
80
|
+
tag = "<img src='#{url}' alt='#{h alt}' height='#{size}' width='#{size}'#{" class='#{options[:class]}'" if options[:class]}>"
|
81
|
+
end
|
82
|
+
|
83
|
+
tag
|
25
84
|
end
|
26
85
|
|
27
|
-
#
|
86
|
+
# Reformats the date into a user friendly date with html entities
|
28
87
|
#
|
29
88
|
# @param [#strftime] date object to format nicely
|
30
89
|
# @return [String] html string formatted using
|
@@ -33,116 +92,118 @@ module Ginatra
|
|
33
92
|
date.strftime("%b %d, %Y – %H:%M")
|
34
93
|
end
|
35
94
|
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# Internally, it calls the +#partial+ method
|
39
|
-
# @see Sinatra::Partials#partial
|
40
|
-
#
|
41
|
-
# @param [Grit::Actor] actor the Grit Actor Object
|
42
|
-
# @param [#to_s] role the role that the object has.
|
43
|
-
# @param [#strftime] date the date that the actor acted on.
|
95
|
+
# Returns an html time tag for the given time
|
44
96
|
#
|
45
|
-
# @
|
46
|
-
|
47
|
-
|
97
|
+
# @param [Time] time object
|
98
|
+
# @return [String] time tag formatted using
|
99
|
+
# +"%B %d, %Y %H:%M"+
|
100
|
+
def time_tag(time)
|
101
|
+
datetime = time.strftime('%Y-%m-%dT%H:%M:%S%z')
|
102
|
+
title = time.strftime('%Y-%m-%d %H:%M:%S')
|
103
|
+
"<time datetime='#{datetime}' title='#{title}'>#{time.strftime('%B %d, %Y %H:%M')}</time>"
|
48
104
|
end
|
49
105
|
|
50
|
-
#
|
106
|
+
# Returns a string including the link to download a patch for a certain
|
107
|
+
# commit to the repo
|
51
108
|
#
|
52
|
-
#
|
53
|
-
#
|
109
|
+
# @param [Rugged::Commit] commit the commit you want a patch for
|
110
|
+
# @param [String] repo_param the url-sanitised name for the repo
|
111
|
+
# (for the link path)
|
54
112
|
#
|
55
|
-
# @
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
if commit.author.name != commit.committer.name
|
60
|
-
o = actor_box(commit.author, :author, commit.authored_date) + o
|
61
|
-
end
|
113
|
+
# @return [String] the HTML link to the patch
|
114
|
+
def patch_link(commit, repo_param)
|
115
|
+
patch_url = prefix_url("#{repo_param}/commit/#{commit.oid}.patch")
|
116
|
+
"<a href='#{patch_url}'>Download Patch</a>"
|
62
117
|
end
|
63
118
|
|
64
|
-
#
|
119
|
+
# Spits out a HTML link to the atom feed for a given ref of a given repo
|
65
120
|
#
|
66
|
-
# @param [
|
67
|
-
# @param [String]
|
68
|
-
# (for the link path)
|
121
|
+
# @param [Sting] repo_param the url-sanitised-name of a given repo
|
122
|
+
# @param [String] ref the ref to link to.
|
69
123
|
#
|
70
|
-
# @return [String] HTML link to the
|
71
|
-
def
|
72
|
-
|
73
|
-
"<a class=\"ref #{ref_class}\" href=\"" + prefix_url("#{repo_param}/#{ref.name}") + "\">#{ref.name}</a>"
|
124
|
+
# @return [String] the HTML containing the link to the feed.
|
125
|
+
def atom_feed_url(repo_param, ref=nil)
|
126
|
+
ref.nil? ? prefix_url("#{repo_param}.atom") : prefix_url("#{repo_param}/#{ref}.atom")
|
74
127
|
end
|
75
128
|
|
76
|
-
#
|
129
|
+
# Returns a HTML (+<ul>+) list of the files modified in a given commit.
|
77
130
|
#
|
78
|
-
#
|
131
|
+
# It includes classes for added/modified/deleted and also anchor links
|
132
|
+
# to the diffs for further down the page.
|
79
133
|
#
|
80
|
-
# @param [
|
81
|
-
# @param [String] repo_param the url-sanitised-name for the repo
|
82
|
-
# (for the link path)
|
134
|
+
# @param [Rugged::Commit] commit the commit you want the list of files for
|
83
135
|
#
|
84
|
-
# @return [String]
|
85
|
-
def
|
86
|
-
|
136
|
+
# @return [String] a +<ul>+ with lots of +<li>+ children.
|
137
|
+
def file_listing(diff)
|
138
|
+
list = []
|
139
|
+
diff.deltas.each_with_index do |delta, index|
|
140
|
+
if delta.deleted?
|
141
|
+
list << "<li class='deleted'><span class='icon-remove' title='deleted'></span> <a href='#file-#{index + 1}'>#{delta.new_file[:path]}</a></li>"
|
142
|
+
elsif delta.added?
|
143
|
+
list << "<li class='added'><span class='icon-ok' title='added'></span> <a href='#file-#{index + 1}'>#{delta.new_file[:path]}</a></li>"
|
144
|
+
elsif delta.modified?
|
145
|
+
list << "<li class='changed'><span class='icon-edit' title='modified'></span> <a href='#file-#{index + 1}'>#{delta.new_file[:path]}</a></li>"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
"<ul class='unstyled'>#{list.join}</ul>"
|
87
149
|
end
|
88
150
|
|
89
|
-
#
|
90
|
-
# tree of the repo
|
151
|
+
# Highlights commit diff
|
91
152
|
#
|
92
|
-
# @param [
|
93
|
-
# @param [String] repo_param the url-sanitised-name of the repo
|
94
|
-
# (for the link path)
|
153
|
+
# @param [Rugged::Hunk] diff hunk for highlighting
|
95
154
|
#
|
96
|
-
# @return [String]
|
97
|
-
def
|
98
|
-
|
99
|
-
|
155
|
+
# @return [String] highlighted HTML.code
|
156
|
+
def highlight_diff(hunk)
|
157
|
+
lines = []
|
158
|
+
lines << hunk.header
|
100
159
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
160
|
+
hunk.each_line do |line|
|
161
|
+
if line.context?
|
162
|
+
lines << " #{line.content}"
|
163
|
+
elsif line.deletion?
|
164
|
+
lines << "- #{line.content}"
|
165
|
+
elsif line.addition?
|
166
|
+
lines << "+ #{line.content}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
formatter = Rouge::Formatters::HTML.new
|
171
|
+
lexer = Rouge::Lexers::Diff.new
|
172
|
+
|
173
|
+
source = lines.join
|
174
|
+
encoding = source.encoding
|
175
|
+
source = source.force_encoding(Encoding::UTF_8)
|
176
|
+
|
177
|
+
hd = formatter.format lexer.lex(source)
|
178
|
+
hd.force_encoding encoding
|
111
179
|
end
|
112
180
|
|
113
|
-
#
|
114
|
-
#
|
115
|
-
# It includes classes for added/altered/deleted and also anchor links
|
116
|
-
# to the diffs for further down the page.
|
181
|
+
# Highlights blob source
|
117
182
|
#
|
118
|
-
# @param [
|
183
|
+
# @param [Rugged::Blob] blob to highlight source
|
119
184
|
#
|
120
|
-
# @return [String]
|
121
|
-
def
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
%(<li class='file_rm'><a href='#file_#{count}'>#{diff.a_path}</a></li>)
|
129
|
-
else
|
130
|
-
cla = diff.new_file ? "add" : "diff"
|
131
|
-
%(<li class='file_#{cla}'><a href='#file_#{count}'>#{diff.a_path}</a></li>)
|
132
|
-
end
|
185
|
+
# @return [String] highlighted HTML.code
|
186
|
+
def highlight_source(source, filename='')
|
187
|
+
source = source.force_encoding(Encoding::UTF_8)
|
188
|
+
formatter = Rouge::Formatters::HTML.new(line_numbers: true, wrap: false)
|
189
|
+
lexer = Rouge::Lexer.guess_by_filename(filename)
|
190
|
+
|
191
|
+
if lexer == Rouge::Lexers::PlainText
|
192
|
+
lexer = Rouge::Lexer.guess_by_source(source) || Rouge::Lexers::PlainText
|
133
193
|
end
|
134
|
-
|
194
|
+
|
195
|
+
formatter.format lexer.lex(source)
|
135
196
|
end
|
136
197
|
|
137
198
|
# Formats the text to remove multiple spaces and newlines, and then inserts
|
138
199
|
# HTML linebreaks.
|
139
200
|
#
|
140
|
-
#
|
141
|
-
# and simplified to just use <p> tags without any options, then modified
|
201
|
+
# Borrowed from Rails: ActionView::Helpers::TextHelper#simple_format
|
202
|
+
# and simplified to just use <p> tags without any options, then modified
|
142
203
|
# more later.
|
143
204
|
#
|
144
205
|
# @param [String] text the text you want formatted
|
145
|
-
#
|
206
|
+
#
|
146
207
|
# @return [String] the formatted text
|
147
208
|
def simple_format(text)
|
148
209
|
text.gsub!(/ +/, " ")
|
@@ -151,47 +212,16 @@ module Ginatra
|
|
151
212
|
text
|
152
213
|
end
|
153
214
|
|
154
|
-
# Cleans up the particularly volatile parts of HTML
|
155
|
-
# and replaces them with their entities. Replaces the following
|
156
|
-
# characters:
|
157
|
-
# - &
|
158
|
-
# - >
|
159
|
-
# - <
|
160
|
-
# - '
|
161
|
-
#
|
162
|
-
# If you are using this with #simple_format, do not forget to call
|
163
|
-
# this one first, then put in unsanitised linebreaks. The other way around
|
164
|
-
# is full of fail.
|
165
|
-
#
|
166
|
-
# stolen from rails: ERB::Util
|
167
|
-
#
|
168
|
-
# @see Ginatra::Helpers#simple_format
|
169
|
-
#
|
170
|
-
# @param [#to_s] clean_me the object to clean.
|
171
|
-
#
|
172
|
-
# @return [String] the cleaned html text.
|
173
|
-
def html_escape(clean_me)
|
174
|
-
clean_me.to_s.gsub(/[&"<>]/) do |special|
|
175
|
-
{ '&' => '&',
|
176
|
-
'>' => '>',
|
177
|
-
'<' => '<',
|
178
|
-
'"' => '"' }[special]
|
179
|
-
end
|
180
|
-
end
|
181
|
-
alias :h :html_escape
|
182
|
-
|
183
215
|
# Truncates a given text to a certain number of letters, including a special ending if needed.
|
184
216
|
#
|
185
|
-
# Stolen and bastardised from rails
|
186
|
-
#
|
187
217
|
# @param [String] text the text to truncate
|
188
218
|
# @option options [Integer] :length (30) the length you want the output string
|
189
219
|
# @option options [String] :omission ("...") the string to show an omission.
|
190
220
|
#
|
191
221
|
# @return [String] the truncated text.
|
192
222
|
def truncate(text, options={})
|
193
|
-
|
194
|
-
|
223
|
+
options[:length] ||= 30
|
224
|
+
options[:omission] ||= "..."
|
195
225
|
|
196
226
|
if text
|
197
227
|
l = options[:length] - options[:omission].length
|
@@ -203,32 +233,17 @@ module Ginatra
|
|
203
233
|
|
204
234
|
# Returns the rfc representation of a date, for use in the atom feeds.
|
205
235
|
#
|
206
|
-
# stolen from Marley
|
207
|
-
#
|
208
236
|
# @param [DateTime] datetime the date to format
|
209
237
|
# @return [String] the formatted datetime
|
210
238
|
def rfc_date(datetime)
|
211
239
|
datetime.strftime("%Y-%m-%dT%H:%M:%SZ") # 2003-12-13T18:30:02Z
|
212
240
|
end
|
213
241
|
|
214
|
-
# Returns the Hostname of the given install.
|
215
|
-
# used in the atom feeds.
|
242
|
+
# Returns the Hostname of the given install, for use in the atom feeds.
|
216
243
|
#
|
217
|
-
# stolen from Marley
|
218
|
-
#
|
219
244
|
# @return [String] the hostname of the server. Respects HTTP-X-Forwarded-For
|
220
245
|
def hostname
|
221
246
|
(request.env['HTTP_X_FORWARDED_SERVER'] =~ /[a-z]*/) ? request.env['HTTP_X_FORWARDED_SERVER'] : request.env['HTTP_HOST']
|
222
247
|
end
|
223
|
-
|
224
|
-
# Spits out a HTML link to the atom feed for a given ref of a given repo
|
225
|
-
#
|
226
|
-
# @param [Sting] repo_param the url-sanitised-name of a given repo
|
227
|
-
# @param [String] ref the ref to link to.
|
228
|
-
#
|
229
|
-
# @return [String] the HTML containing the link to the feed.
|
230
|
-
def atom_feed_link(repo_param, ref=nil)
|
231
|
-
"<a href=\"" + prefix_url("#{repo_param}#{"/#{ref}" if !ref.nil?}.atom") + "\" title=\"Atom Feed\" class=\"atom\">Feed</a>"
|
232
|
-
end
|
233
248
|
end
|
234
249
|
end
|