activate-admin 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.components +9 -0
- data/.gitignore +29 -0
- data/Gemfile +57 -0
- data/Gemfile.lock +184 -0
- data/Procfile +1 -0
- data/README.md +54 -0
- data/Rakefile +6 -0
- data/activate-admin.gemspec +19 -0
- data/admin/app.rb +160 -0
- data/admin/assets/fonts/FontAwesome.otf +0 -0
- data/admin/assets/fonts/fontawesome-webfont.eot +0 -0
- data/admin/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/admin/assets/fonts/fontawesome-webfont.woff +0 -0
- data/admin/assets/javascripts/bootstrap-wysihtml5-0.0.2.js +321 -0
- data/admin/assets/javascripts/bootstrap.min.js +6 -0
- data/admin/assets/javascripts/jquery-1.9.1.min.js +5 -0
- data/admin/assets/javascripts/jquery-migrate-1.1.1.js +511 -0
- data/admin/assets/javascripts/jquery-ujs.js +95 -0
- data/admin/assets/javascripts/jquery.ba-bbq.min.js +18 -0
- data/admin/assets/javascripts/wysihtml5-0.3.0.js +9530 -0
- data/admin/assets/stylesheets/bootstrap-responsive.min.css +9 -0
- data/admin/assets/stylesheets/bootstrap-wysihtml5-0.0.2.css +44 -0
- data/admin/assets/stylesheets/bootstrap.min.css +9 -0
- data/admin/assets/stylesheets/font-awesome.min.css +34 -0
- data/admin/helpers/helpers.rb +19 -0
- data/admin/views/build.erb +111 -0
- data/admin/views/home.erb +24 -0
- data/admin/views/index.erb +108 -0
- data/admin/views/layouts/application.erb +75 -0
- data/admin/views/login_page.erb +31 -0
- data/config/apps.rb +5 -0
- data/config/boot.rb +26 -0
- data/config/mongoid.yml +14 -0
- data/config/navigation.rb +3 -0
- data/config.ru +9 -0
- data/lib/activate-admin/version.rb +3 -0
- data/lib/activate-admin.rb +6 -0
- data/lib/assetpack_patch.rb +18 -0
- data/lib/date_formats.rb +11 -0
- data/lib/datetime_helpers.rb +32 -0
- data/lib/dragonfly.rb +30 -0
- data/lib/kaminari/_first_page.html.erb +12 -0
- data/lib/kaminari/_gap.html.erb +8 -0
- data/lib/kaminari/_last_page.html.erb +13 -0
- data/lib/kaminari/_next_page.html.erb +13 -0
- data/lib/kaminari/_page.html.erb +12 -0
- data/lib/kaminari/_paginator.html.erb +25 -0
- data/lib/kaminari/_prev_page.html.erb +13 -0
- data/lib/kaminari.rb +51 -0
- data/lib/param_helpers.rb +41 -0
- metadata +113 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
|
2
|
+
<div class="page-header">
|
3
|
+
<h1><%=human_model_name(model).pluralize%></h1>
|
4
|
+
<a href="<%=url_for(:new, :model => model.to_s)%>" class="btn btn-primary"><i class="icon-pencil"></i> New</a>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<div class="row-fluid">
|
8
|
+
<div class="span6">
|
9
|
+
<p>
|
10
|
+
<%= page_entries_info @resources %>
|
11
|
+
<a class="btn" title="Download results as csv" target="_blank" href="<%=url_for(:index, params.merge(:model => model.to_s, :format => :csv))%>"><i class="icon-download-alt"></i></a>
|
12
|
+
</p>
|
13
|
+
</div>
|
14
|
+
<div class="span6" style="text-align: right">
|
15
|
+
<form style="display: inline" class="form-search">
|
16
|
+
<%= search_field_tag :q, :class => 'input-medium search-query', :value => @q %>
|
17
|
+
<% @f.each { |k,v| %>
|
18
|
+
<%= hidden_field_tag :"f[#{k}]", :value => v %>
|
19
|
+
<% } if @f %>
|
20
|
+
<%= hidden_field_tag :o, :value => @o %>
|
21
|
+
<%= hidden_field_tag :d, :value => @d %>
|
22
|
+
<button type="submit" name="qf" value="search" class="btn">Search</button>
|
23
|
+
<button type="submit" name="qf" value="eval" class="btn">Eval</button>
|
24
|
+
</form>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
|
28
|
+
<style>
|
29
|
+
th[data-fieldname] a { color:black; text-decoration: none !important }
|
30
|
+
a.fn, a.odn { visibility:hidden; }
|
31
|
+
</style>
|
32
|
+
<script>
|
33
|
+
$(function() {
|
34
|
+
var params = $.deparam.querystring();
|
35
|
+
$('th').hover(function() { $('a.fn, a.odn', this).css('visibility','visible') }, function() { $('a.fn, a.odn', this).css('visibility','hidden') });
|
36
|
+
$('a.od').click(function() {
|
37
|
+
params['o'] = $(this).closest('th').data('fieldname')
|
38
|
+
params['d'] = params['d'] == 'asc' ? 'desc' : 'asc'
|
39
|
+
location.assign(location.pathname+'?'+$.param(params));
|
40
|
+
});
|
41
|
+
$('a.f').click(function() {
|
42
|
+
console.log(this);
|
43
|
+
if (!params['f'])
|
44
|
+
params['f'] = {}
|
45
|
+
params['f'][$(this).closest('th').data('fieldname')] = prompt('Search for:');
|
46
|
+
location.assign(location.pathname+'?'+$.param(params));
|
47
|
+
});
|
48
|
+
});
|
49
|
+
</script>
|
50
|
+
<table class="table table-striped table-condensed">
|
51
|
+
<thead>
|
52
|
+
<tr>
|
53
|
+
<% model.fields_for_index.each { |fieldname| %>
|
54
|
+
<th data-fieldname="<%=fieldname%>">
|
55
|
+
<%= model.human_attribute_name(fieldname) %>
|
56
|
+
|
57
|
+
<% if @o == fieldname.to_sym %>
|
58
|
+
<a title="Ordered by <%=fieldname%>; click to reverse" href="javascript:;" class="od">
|
59
|
+
<% if @d == :asc %>
|
60
|
+
<i class="icon-caret-down"></i>
|
61
|
+
<% elsif @d == :desc %>
|
62
|
+
<i class="icon-caret-up"></i>
|
63
|
+
<% end %>
|
64
|
+
</a>
|
65
|
+
<% else %>
|
66
|
+
<a title="Order by <%=fieldname%>" href="javascript:;" class="od odn">
|
67
|
+
<i class="icon-caret-right"></i>
|
68
|
+
</a>
|
69
|
+
<% end %>
|
70
|
+
|
71
|
+
<% if @f and @f[fieldname] %>
|
72
|
+
<a title="Searching for '<%=@f[fieldname]%>'; click to search again" href="javascript:;" class="f"><i class="icon-search"></i></a>
|
73
|
+
<% else %>
|
74
|
+
<a title="Search in <%=fieldname%>" href="javascript:;" class="f fn"><i class="icon-search"></i></a>
|
75
|
+
<% end %>
|
76
|
+
</th>
|
77
|
+
<% } %>
|
78
|
+
<th style="width: 70px"></th>
|
79
|
+
<th style="width: 88px"></th>
|
80
|
+
</tr>
|
81
|
+
</thead>
|
82
|
+
<tbody>
|
83
|
+
<% @resources.each { |resource| %>
|
84
|
+
<tr>
|
85
|
+
<% model.fields_for_index.each { |fieldname| %>
|
86
|
+
<td>
|
87
|
+
<% if fieldname.match(/_id/) && Object.const_defined?(fieldname.to_s.gsub('_id','').camelize) && resource.send(fieldname) %>
|
88
|
+
<a target="_blank" href="<%=url_for(:edit, :model => fieldname.to_s.gsub('_id','').camelize.constantize, :id => resource.send(fieldname))%>"><%= fieldname.to_s.gsub('_id','').camelize.constantize.find(resource.send(fieldname)).lookup %></a>
|
89
|
+
<% elsif fieldname.match(/_url/) %>
|
90
|
+
<a href="<%=resource.send(fieldname)%>"><%=resource.send(fieldname)%></a>
|
91
|
+
<% else %>
|
92
|
+
<%= truncate(strip_tags(resource.send(fieldname).to_s), :length => 30) %>
|
93
|
+
<% end %>
|
94
|
+
</td>
|
95
|
+
<% } %>
|
96
|
+
<td>
|
97
|
+
<a href="<%=url_for(:edit, :model => model.to_s, :id => resource.id)%>" class="btn"><i class="icon-edit"></i> Edit</a>
|
98
|
+
</td>
|
99
|
+
<td>
|
100
|
+
<a class="btn btn-danger" data-confirm="Are you sure you want to delete this <%=human_model_name(model).downcase%>?" href="<%=url_for(:destroy, :model => model.to_s, :id => resource.id)%>"><i class="icon-trash"></i> Delete</a>
|
101
|
+
</td>
|
102
|
+
</tr>
|
103
|
+
<% } %>
|
104
|
+
</tbody>
|
105
|
+
</table>
|
106
|
+
|
107
|
+
<%= paginate @resources %>
|
108
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
|
8
|
+
<title>ActivateAdmin</title>
|
9
|
+
|
10
|
+
<%= (css :app).html_safe %>
|
11
|
+
<%= (js :app).html_safe %>
|
12
|
+
|
13
|
+
<style>
|
14
|
+
body { padding: 60px 0; }
|
15
|
+
.page-header { margin-top: 0; padding-bottom: 10px }
|
16
|
+
.page-header h1 { display: inline }
|
17
|
+
.page-header a { margin-left: 10px; position: relative; top: -6px }
|
18
|
+
</style>
|
19
|
+
|
20
|
+
</head>
|
21
|
+
<body>
|
22
|
+
<!--[if lt IE 7]><p class=chromeframe>Your browser is <em>ancient!</em> <a href="http://browsehappy.com/">Upgrade to a different browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a> to experience this site.</p><![endif]-->
|
23
|
+
|
24
|
+
<div class="navbar navbar-fixed-top">
|
25
|
+
<div class="navbar-inner">
|
26
|
+
<div class="container-fluid">
|
27
|
+
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
28
|
+
<span class="icon-bar"></span>
|
29
|
+
<span class="icon-bar"></span>
|
30
|
+
<span class="icon-bar"></span>
|
31
|
+
</a>
|
32
|
+
<a style="font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;" class="brand" href="<%=url_for(:home)%>">ActivateAdmin</a>
|
33
|
+
<% if current_account %>
|
34
|
+
<div class="nav-collapse">
|
35
|
+
<%= render_navigation :items => models.map { |model|
|
36
|
+
{:key => :left, :name => human_model_name(model).pluralize, :url => url_for(:index, :model => model.to_s), :options => {:container_class => 'nav'}}
|
37
|
+
}
|
38
|
+
%>
|
39
|
+
<ul class="nav pull-right">
|
40
|
+
<li><a href="<%=url_for(:logout)%>">Sign out</a></li>
|
41
|
+
</ul>
|
42
|
+
</div><!--/.nav-collapse -->
|
43
|
+
<% end %>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
|
48
|
+
<div class="container-fluid">
|
49
|
+
<div class="row-fluid">
|
50
|
+
<div class="span12">
|
51
|
+
|
52
|
+
<div style="z-index: 1040; width: 40%; margin-left: -20%; left: 50%; position: absolute; margin-top: -40px">
|
53
|
+
<% {:error => 'alert-error', :warning => '', :notice => 'alert-info'}.each { |k,v| %>
|
54
|
+
<% if flash[k] %>
|
55
|
+
<div class="fade in alert <%=v%>" style="box-shadow: 1px 1px 3px #ccc;">
|
56
|
+
<button data-dismiss="alert" class="close" type="button">×</button>
|
57
|
+
<%= flash[k].html_safe %>
|
58
|
+
</div>
|
59
|
+
<% end %>
|
60
|
+
<% } %>
|
61
|
+
</div>
|
62
|
+
<script>
|
63
|
+
$(function() {
|
64
|
+
$(".alert").alert()
|
65
|
+
window.setTimeout(function() { $(".alert").alert('close'); }, 3000);
|
66
|
+
});
|
67
|
+
</script>
|
68
|
+
|
69
|
+
<%= yield %>
|
70
|
+
</div>
|
71
|
+
</div>
|
72
|
+
</div>
|
73
|
+
|
74
|
+
</body>
|
75
|
+
</html>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
<% form_tag url_for(:login), :class => 'form-horizontal' do %>
|
3
|
+
|
4
|
+
<div class="control-group">
|
5
|
+
<label class="control-label">Email</label>
|
6
|
+
<div class="controls">
|
7
|
+
<%= text_field_tag :email, :value => params[:email] %>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="control-group">
|
12
|
+
<label class="control-label">Password</label>
|
13
|
+
<div class="controls">
|
14
|
+
<%= password_field_tag :password, :value => params[:password] %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<% if Padrino.env == :development %>
|
19
|
+
<div class="control-group">
|
20
|
+
<label class="control-label">Bypass login?</label>
|
21
|
+
<div class="controls">
|
22
|
+
<%= check_box_tag :bypass %>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<div class="form-actions">
|
28
|
+
<button class="btn btn-primary" type="submit">Sign in</button>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<% end %>
|
data/config/apps.rb
ADDED
data/config/boot.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Defines our constants
|
2
|
+
PADRINO_ENV = ENV['PADRINO_ENV'] ||= ENV['RACK_ENV'] ||= 'development' unless defined?(PADRINO_ENV)
|
3
|
+
PADRINO_ROOT = File.expand_path('../..', __FILE__) unless defined?(PADRINO_ROOT)
|
4
|
+
|
5
|
+
# Load our dependencies
|
6
|
+
require 'rubygems' unless defined?(Gem)
|
7
|
+
require 'bundler/setup'
|
8
|
+
require 'pp'
|
9
|
+
require 'csv'
|
10
|
+
require 'backtrace_shortener'
|
11
|
+
BacktraceShortener.monkey_patch_the_exception_class!
|
12
|
+
BacktraceShortener.filters.unshift(Proc.new do |backtrace|
|
13
|
+
backtrace.reject { |line| line.include?(Gem.dir) }
|
14
|
+
end)
|
15
|
+
Bundler.require(:default, PADRINO_ENV)
|
16
|
+
|
17
|
+
Padrino.before_load do
|
18
|
+
end
|
19
|
+
|
20
|
+
Padrino.after_load do
|
21
|
+
end
|
22
|
+
|
23
|
+
Padrino.load!
|
24
|
+
|
25
|
+
Mongoid.load!("#{ActivateAdmin.root}/config/mongoid.yml")
|
26
|
+
Mongoid.raise_not_found_error = false
|
data/config/mongoid.yml
ADDED
data/config.ru
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Sinatra::AssetPack::Package
|
2
|
+
|
3
|
+
def production_path
|
4
|
+
app_root = Padrino.mounted_apps.find{ |app| app.name == @assets.app.name }.uri_root
|
5
|
+
asset_path = add_cache_buster( @path, *files )
|
6
|
+
app_root == '/' ? asset_path : ( app_root + asset_path )
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_development_html(options={})
|
10
|
+
app_root = Padrino.mounted_apps.find{ |app| app.name == @assets.app.name }.uri_root
|
11
|
+
path_prefix = app_root == '/' ? '' : app_root
|
12
|
+
paths_and_files.map { |path, file|
|
13
|
+
path = add_cache_buster(path_prefix + path, file) # app.css => app.829378.css
|
14
|
+
link_tag(path, options)
|
15
|
+
}.join("\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/date_formats.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'active_support/core_ext/integer/inflections'
|
2
|
+
|
3
|
+
Time::DATE_FORMATS.merge!(
|
4
|
+
:default => lambda { |time| time.to_s(:date) + ', ' + time.to_s(:time) },
|
5
|
+
:date => lambda { |time| time.to_date.to_s },
|
6
|
+
:time => lambda { |time| time.strftime("#{(t = time.hour%12) == 0 ? 12 : t}:%M#{time.strftime('%p').downcase}") }
|
7
|
+
)
|
8
|
+
|
9
|
+
Date::DATE_FORMATS.merge!(
|
10
|
+
:default => lambda { |date| date.strftime("%a #{date.day.ordinalize} %b %Y") }
|
11
|
+
)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DatetimeHelpers
|
2
|
+
|
3
|
+
def datetime_select_tags(name, options)
|
4
|
+
v = options[:value] || Time.zone.now
|
5
|
+
c = options[:class]
|
6
|
+
id = options[:id]
|
7
|
+
s = []
|
8
|
+
s << "<style>.datetime select { width: auto }</style>"
|
9
|
+
s << "<span id=\"#{id if id}\" class=\"datetime #{c if c}\">"
|
10
|
+
s << select_tag(:"#{name}[day]", :options => (1..31).to_a, :selected => v.day )
|
11
|
+
s << select_tag(:"#{name}[month]", :options => Date::MONTHNAMES[1..-1].each_with_index.map { |x,i| [x,i+1] }, :selected => v.month)
|
12
|
+
s << select_tag(:"#{name}[year]", :options => (2012..2020).to_a, :selected => v.year )
|
13
|
+
s << '@'
|
14
|
+
s << select_tag(:"#{name}[hour]", :options => (0..23).to_a.map { |x| [x < 10 ? "0#{x}" : x,x] }, :selected => v.hour )
|
15
|
+
s << ':'
|
16
|
+
s << select_tag(:"#{name}[min]", :options => (0..59).to_a.map { |x| [x < 10 ? "0#{x}" : x,x] }, :selected => v.min )
|
17
|
+
s << '</span>'
|
18
|
+
s.join(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
def compact_time_ago(t)
|
22
|
+
d = Time.now - t
|
23
|
+
if d < 1.day
|
24
|
+
time_ago_in_words(t) + ' ago'
|
25
|
+
elsif d < 3.days
|
26
|
+
t.strftime('%A') + " at #{t.to_s(:time)}"
|
27
|
+
else
|
28
|
+
t
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/dragonfly.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
if defined? Dragonfly
|
2
|
+
|
3
|
+
app = Dragonfly[:dragonfly].configure_with(:imagemagick) do |c|
|
4
|
+
c.url_format = '/media/:job/:basename.:format'
|
5
|
+
end
|
6
|
+
|
7
|
+
app.analyser.register(Dragonfly::Analysis::FileCommandAnalyser)
|
8
|
+
|
9
|
+
if Padrino.env == :production
|
10
|
+
# app.datastore = Dragonfly::DataStorage::S3DataStore.new
|
11
|
+
# app.datastore.configure do |d|
|
12
|
+
# d.bucket_name = ENV['S3_BUCKET_NAME']
|
13
|
+
# d.access_key_id = ENV['S3_ACCESS_KEY']
|
14
|
+
# d.secret_access_key = ENV['S3_SECRET']
|
15
|
+
# end
|
16
|
+
app.datastore = Dragonfly::DataStorage::MongoDataStore.new
|
17
|
+
app.datastore.configure do |c|
|
18
|
+
c.host = ENV['MONGOHQ_URL'].split('@').last.split(':').first
|
19
|
+
c.port = ENV['MONGOHQ_URL'].split('@').last.split(':').last.split('/').first
|
20
|
+
c.database = ENV['MONGOHQ_URL'].split('/')[3]
|
21
|
+
c.username = ENV['MONGOHQ_URL'].split('://').last.split(':').first
|
22
|
+
c.password = ENV['MONGOHQ_URL'].split('://').last.split('@').first.split(':').last
|
23
|
+
end
|
24
|
+
else
|
25
|
+
app.datastore = Dragonfly::DataStorage::MongoDataStore.new
|
26
|
+
end
|
27
|
+
|
28
|
+
app.define_macro_on_include(Mongoid::Document, :dragonfly_accessor)
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%# Link to the "First" page
|
2
|
+
- available local variables
|
3
|
+
url: url to the first page
|
4
|
+
current_page: a page object for the currently displayed page
|
5
|
+
num_pages: total number of pages
|
6
|
+
per_page: number of items to fetch per page
|
7
|
+
remote: data-remote
|
8
|
+
-%>
|
9
|
+
|
10
|
+
<li class="first <%='disabled' if current_page.first?%>">
|
11
|
+
<%= link_to raw(t 'views.pagination.first'), url, :remote => remote %>
|
12
|
+
</li>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%# Non-link tag that stands for skipped pages...
|
2
|
+
- available local variables
|
3
|
+
current_page: a page object for the currently displayed page
|
4
|
+
num_pages: total number of pages
|
5
|
+
per_page: number of items to fetch per page
|
6
|
+
remote: data-remote
|
7
|
+
-%>
|
8
|
+
<li class="page gap disabled"><a href="#" onclick="return false;"><%= raw(t 'views.pagination.truncate') %></a></li>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%# Link to the "Last" page
|
2
|
+
- available local variables
|
3
|
+
url: url to the last page
|
4
|
+
current_page: a page object for the currently displayed page
|
5
|
+
num_pages: total number of pages
|
6
|
+
per_page: number of items to fetch per page
|
7
|
+
remote: data-remote
|
8
|
+
-%>
|
9
|
+
|
10
|
+
<li class="last next <%='disabled' if current_page.last?%>"><%# "next" class present for border styling in twitter bootstrap %>
|
11
|
+
<%= link_to raw(t 'views.pagination.last'), url, {:remote => remote} %>
|
12
|
+
</li>
|
13
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%# Link to the "Next" page
|
2
|
+
- available local variables
|
3
|
+
url: url to the next page
|
4
|
+
current_page: a page object for the currently displayed page
|
5
|
+
num_pages: total number of pages
|
6
|
+
per_page: number of items to fetch per page
|
7
|
+
remote: data-remote
|
8
|
+
-%>
|
9
|
+
|
10
|
+
<li class="next_page <%='disabled' if current_page.last?%>">
|
11
|
+
<%= link_to raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote %>
|
12
|
+
</li>
|
13
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%# Link showing page number
|
2
|
+
- available local variables
|
3
|
+
page: a page object for "this" page
|
4
|
+
url: url to this page
|
5
|
+
current_page: a page object for the currently displayed page
|
6
|
+
num_pages: total number of pages
|
7
|
+
per_page: number of items to fetch per page
|
8
|
+
remote: data-remote
|
9
|
+
-%>
|
10
|
+
<li class="page<%= ' active' if page.current? %>">
|
11
|
+
<%= link_to page, url, opts = {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
|
12
|
+
</li>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<%# The container tag
|
2
|
+
- available local variables
|
3
|
+
current_page: a page object for the currently displayed page
|
4
|
+
num_pages: total number of pages
|
5
|
+
per_page: number of items to fetch per page
|
6
|
+
remote: data-remote
|
7
|
+
paginator: the paginator that renders the pagination tags inside
|
8
|
+
-%>
|
9
|
+
<%= paginator.render do -%>
|
10
|
+
<div class="pagination">
|
11
|
+
<ul>
|
12
|
+
<%= first_page_tag %>
|
13
|
+
<%= prev_page_tag %>
|
14
|
+
<% each_page do |page| -%>
|
15
|
+
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
|
16
|
+
<%= page_tag page %>
|
17
|
+
<% elsif !page.was_truncated? -%>
|
18
|
+
<%= gap_tag %>
|
19
|
+
<% end -%>
|
20
|
+
<% end -%>
|
21
|
+
<%= next_page_tag %>
|
22
|
+
<%= last_page_tag %>
|
23
|
+
</ul>
|
24
|
+
</div>
|
25
|
+
<% end -%>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%# Link to the "Previous" page
|
2
|
+
- available local variables
|
3
|
+
url: url to the previous page
|
4
|
+
current_page: a page object for the currently displayed page
|
5
|
+
num_pages: total number of pages
|
6
|
+
per_page: number of items to fetch per page
|
7
|
+
remote: data-remote
|
8
|
+
-%>
|
9
|
+
|
10
|
+
<li class="prev <%='disabled' if current_page.first?%>">
|
11
|
+
<%= link_to raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote %>
|
12
|
+
</li>
|
13
|
+
|
data/lib/kaminari.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
if defined? Kaminari
|
2
|
+
module Kaminari::Helpers
|
3
|
+
module SinatraHelpers
|
4
|
+
|
5
|
+
class ActionViewTemplateProxy
|
6
|
+
def render(*args)
|
7
|
+
base = ActionView::Base.new.tap do |a|
|
8
|
+
a.view_paths << File.expand_path("#{ActivateAdmin.root}/lib", __FILE__)
|
9
|
+
end
|
10
|
+
base.render(*args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def page_entries_info(collection, options = {})
|
15
|
+
entry_name = if options[:entry_name]
|
16
|
+
options[:entry_name]
|
17
|
+
elsif collection.empty? || collection.is_a?(Array)
|
18
|
+
'entry'
|
19
|
+
else
|
20
|
+
if collection.respond_to? :model # DataMapper
|
21
|
+
collection.model.model_name.human.downcase
|
22
|
+
else # AR
|
23
|
+
collection.model_name.human.downcase
|
24
|
+
end
|
25
|
+
end
|
26
|
+
entry_name = entry_name.pluralize unless collection.total_count == 1
|
27
|
+
|
28
|
+
if collection.total_pages < 2
|
29
|
+
t('helpers.page_entries_info.one_page.display_entries', :entry_name => entry_name, :count => collection.total_count)
|
30
|
+
else
|
31
|
+
first = collection.offset_value + 1
|
32
|
+
last = collection.last_page? ? collection.total_count : collection.offset_value + collection.limit_value
|
33
|
+
t('helpers.page_entries_info.more_pages.display_entries', :entry_name => entry_name, :first => first, :last => last, :total => collection.total_count)
|
34
|
+
end.html_safe
|
35
|
+
end
|
36
|
+
|
37
|
+
module HelperMethods
|
38
|
+
def paginate(scope, options = {}, &block)
|
39
|
+
current_path = env['REQUEST_PATH'] rescue nil
|
40
|
+
current_params = Rack::Utils.parse_query(env['QUERY_STRING']).symbolize_keys rescue {}
|
41
|
+
paginator = Kaminari::Helpers::Paginator.new(
|
42
|
+
ActionViewTemplateProxy.new(:current_params => current_params, :current_path => current_path, :param_name => options[:param_name] || Kaminari.config.param_name),
|
43
|
+
options.reverse_merge(:current_page => scope.current_page, :total_pages => scope.total_pages, :per_page => scope.limit_value, :param_name => Kaminari.config.param_name, :remote => false)
|
44
|
+
)
|
45
|
+
paginator.to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ParamHelpers
|
2
|
+
|
3
|
+
def fix_params!
|
4
|
+
datetime_hashes_to_datetimes!(params)
|
5
|
+
file_hashes_to_files!(params)
|
6
|
+
blanks_to_nils!(params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def datetime_hashes_to_datetimes!(hash)
|
10
|
+
hash.each { |k,v|
|
11
|
+
if v.is_a?(Hash) and [:year, :month, :day, :hour, :min].all? { |x| v.has_key?(x.to_s) }
|
12
|
+
hash[k] = Time.zone.local(v[:year].to_i, v[:month].to_i, v[:day].to_i, v[:hour].to_i, v[:min].to_i)
|
13
|
+
elsif v.is_a?(Hash)
|
14
|
+
datetime_hashes_to_datetimes!(v)
|
15
|
+
end
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def file_hashes_to_files!(hash)
|
20
|
+
hash.each { |k, v|
|
21
|
+
if v.is_a?(Hash) and v[:tempfile]
|
22
|
+
hash[k] = v[:tempfile]
|
23
|
+
elsif v.is_a?(Hash)
|
24
|
+
file_hashes_to_files!(v)
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def blanks_to_nils!(hash)
|
30
|
+
hash.each { |k,v|
|
31
|
+
if v.blank?
|
32
|
+
hash[k] = nil
|
33
|
+
elsif v.is_a? Array
|
34
|
+
v.each_with_index { |x,i| v[i] = nil if x.blank? }.compact!
|
35
|
+
elsif v.is_a? Hash
|
36
|
+
blanks_to_nils!(v)
|
37
|
+
end
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|