sferik-merb-admin 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.markdown +55 -0
- data/Rakefile +69 -0
- data/app/controllers/application.rb +17 -0
- data/app/controllers/forms.rb +85 -0
- data/app/helpers/application_helper.rb +66 -0
- data/app/helpers/forms_helper.rb +112 -0
- data/app/views/forms/_big_decimal.html.erb +8 -0
- data/app/views/forms/_date.html.erb +8 -0
- data/app/views/forms/_date_time.html.erb +8 -0
- data/app/views/forms/_float.html.erb +8 -0
- data/app/views/forms/_integer.html.erb +12 -0
- data/app/views/forms/_string.html.erb +16 -0
- data/app/views/forms/_time.html.erb +8 -0
- data/app/views/forms/_true_class.html.erb +5 -0
- data/app/views/forms/delete.html.erb +12 -0
- data/app/views/forms/edit.html.erb +23 -0
- data/app/views/forms/index.html.erb +22 -0
- data/app/views/forms/list.html.erb +64 -0
- data/app/views/forms/new.html.erb +19 -0
- data/app/views/layout/_message.html.erb +10 -0
- data/app/views/layout/dashboard.html.erb +37 -0
- data/app/views/layout/form.html.erb +51 -0
- data/app/views/layout/list.html.erb +45 -0
- data/lib/merb-admin/merbtasks.rb +103 -0
- data/lib/merb-admin/slicetasks.rb +20 -0
- data/lib/merb-admin/spectasks.rb +53 -0
- data/lib/merb-admin.rb +101 -0
- data/public/images/arrow-down.gif +0 -0
- data/public/images/arrow-up.gif +0 -0
- data/public/images/changelist-bg.gif +0 -0
- data/public/images/changelist-bg_rtl.gif +0 -0
- data/public/images/chooser-bg.gif +0 -0
- data/public/images/chooser_stacked-bg.gif +0 -0
- data/public/images/default-bg-reverse.gif +0 -0
- data/public/images/default-bg.gif +0 -0
- data/public/images/deleted-overlay.gif +0 -0
- data/public/images/icon-no.gif +0 -0
- data/public/images/icon-unknown.gif +0 -0
- data/public/images/icon-yes.gif +0 -0
- data/public/images/icon_addlink.gif +0 -0
- data/public/images/icon_alert.gif +0 -0
- data/public/images/icon_calendar.gif +0 -0
- data/public/images/icon_changelink.gif +0 -0
- data/public/images/icon_clock.gif +0 -0
- data/public/images/icon_deletelink.gif +0 -0
- data/public/images/icon_error.gif +0 -0
- data/public/images/icon_searchbox.png +0 -0
- data/public/images/icon_success.gif +0 -0
- data/public/images/inline-delete-8bit.png +0 -0
- data/public/images/inline-delete.png +0 -0
- data/public/images/inline-restore-8bit.png +0 -0
- data/public/images/inline-restore.png +0 -0
- data/public/images/inline-splitter-bg.gif +0 -0
- data/public/images/nav-bg-grabber.gif +0 -0
- data/public/images/nav-bg-reverse.gif +0 -0
- data/public/images/nav-bg.gif +0 -0
- data/public/images/selector-add.gif +0 -0
- data/public/images/selector-addall.gif +0 -0
- data/public/images/selector-remove.gif +0 -0
- data/public/images/selector-removeall.gif +0 -0
- data/public/images/selector-search.gif +0 -0
- data/public/images/selector_stacked-add.gif +0 -0
- data/public/images/selector_stacked-remove.gif +0 -0
- data/public/images/tool-left.gif +0 -0
- data/public/images/tool-left_over.gif +0 -0
- data/public/images/tool-right.gif +0 -0
- data/public/images/tool-right_over.gif +0 -0
- data/public/images/tooltag-add.gif +0 -0
- data/public/images/tooltag-add_over.gif +0 -0
- data/public/images/tooltag-arrowright.gif +0 -0
- data/public/images/tooltag-arrowright_over.gif +0 -0
- data/public/javascripts/CollapsedFieldsets.js +85 -0
- data/public/javascripts/DateTimeShortcuts.js +255 -0
- data/public/javascripts/RelatedObjectLookups.js +96 -0
- data/public/javascripts/SelectBox.js +111 -0
- data/public/javascripts/SelectFilter2.js +113 -0
- data/public/javascripts/actions.js +39 -0
- data/public/javascripts/calendar.js +143 -0
- data/public/javascripts/core.js +176 -0
- data/public/javascripts/dateparse.js +233 -0
- data/public/javascripts/getElementsBySelector.js +167 -0
- data/public/javascripts/i18n.js +33 -0
- data/public/javascripts/master.js +0 -0
- data/public/javascripts/ordering.js +137 -0
- data/public/javascripts/timeparse.js +94 -0
- data/public/javascripts/urlify.js +140 -0
- data/public/stylesheets/base.css +746 -0
- data/public/stylesheets/changelists.css +269 -0
- data/public/stylesheets/dashboard.css +24 -0
- data/public/stylesheets/forms.css +327 -0
- data/public/stylesheets/global.css +142 -0
- data/public/stylesheets/ie.css +51 -0
- data/public/stylesheets/layout.css +29 -0
- data/public/stylesheets/login.css +54 -0
- data/public/stylesheets/master.css +2 -0
- data/public/stylesheets/null.css +1 -0
- data/public/stylesheets/patch-iewin.css +8 -0
- data/public/stylesheets/rtl.css +206 -0
- data/public/stylesheets/widgets.css +506 -0
- data/spec/controller/forms_spec.rb +41 -0
- data/spec/merb-admin_spec.rb +5 -0
- data/spec/spec_helper.rb +58 -0
- metadata +213 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Erik Michaels-Ober
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# MerbAdmin
|
2
|
+
|
3
|
+
**MerbAdmin is a merb slice that provides an easy-to-use interface for managing your data.**
|
4
|
+
|
5
|
+
It currently offers the features listed [here](http://sferik.tadalist.com/lists/1352791/public).
|
6
|
+
|
7
|
+
## Get it
|
8
|
+
|
9
|
+
At the command prompt, type:
|
10
|
+
|
11
|
+
git clone git://github.com/sferik/merb-admin.git
|
12
|
+
cd merb-admin
|
13
|
+
sudo rake install
|
14
|
+
|
15
|
+
## Install it
|
16
|
+
|
17
|
+
In your app, add the following dependency to `config/dependencies.rb`:
|
18
|
+
|
19
|
+
dependency "merb-admin", "0.1.7"
|
20
|
+
|
21
|
+
Add the following route to `config/router.rb`:
|
22
|
+
|
23
|
+
slice(:MerbAdmin, :name_prefix => nil, :path_prefix => "", :default_routes => false)
|
24
|
+
|
25
|
+
Then, run the following rake task:
|
26
|
+
|
27
|
+
rake slices:merb-admin:install
|
28
|
+
|
29
|
+
## Configure it (optional)
|
30
|
+
|
31
|
+
You can configuring the merb-admin slice in a before_app_loads block:
|
32
|
+
|
33
|
+
Merb::BootLoader.before_app_loads do
|
34
|
+
Merb::Slices::config[:merb_admin][:app_name] = "My App"
|
35
|
+
end
|
36
|
+
|
37
|
+
## Run it
|
38
|
+
|
39
|
+
Start the server:
|
40
|
+
|
41
|
+
merb
|
42
|
+
|
43
|
+
You should now be able to administer your site at [http://localhost:4000/admin](http://localhost:4000/admin).
|
44
|
+
|
45
|
+
Please report any problems you encounter to <sferik@gmail.com> or [@sferik](http://twitter.com/home/?status=@sferik%20) on Twitter.
|
46
|
+
|
47
|
+
## WARNING
|
48
|
+
|
49
|
+
MerbAdmin does not implement any authorization scheme. Make sure to apply authorization logic before deploying to production!
|
50
|
+
|
51
|
+
## Acknowledgements
|
52
|
+
|
53
|
+
Many thanks to [Wilson Miner](http://www.wilsonminer.com) for contributing the stylesheets and javascripts from [Django](http://www.djangoproject.com).
|
54
|
+
|
55
|
+
Also, thanks to [beer](http://www.anchorbrewing.com).
|
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake/gempackagetask"
|
3
|
+
|
4
|
+
require "merb-core"
|
5
|
+
require "merb-core/tasks/merb"
|
6
|
+
|
7
|
+
dependency "dm-core"
|
8
|
+
dependency "merb_datamapper"
|
9
|
+
|
10
|
+
GEM_NAME = "merb-admin"
|
11
|
+
AUTHOR = "Erik Michaels-Ober"
|
12
|
+
EMAIL = "sferik@gmail.com"
|
13
|
+
HOMEPAGE = "http://twitter.com/sferik"
|
14
|
+
SUMMARY = "MerbAdmin is a merb slice that provides an easy-to-use interface for managing your data."
|
15
|
+
GEM_VERSION = "0.1.7"
|
16
|
+
|
17
|
+
spec = Gem::Specification.new do |s|
|
18
|
+
s.rubyforge_project = "merb"
|
19
|
+
s.name = GEM_NAME
|
20
|
+
s.version = GEM_VERSION
|
21
|
+
s.platform = Gem::Platform::RUBY
|
22
|
+
s.has_rdoc = false
|
23
|
+
s.extra_rdoc_files = ["README.markdown", "LICENSE"]
|
24
|
+
s.summary = SUMMARY
|
25
|
+
s.description = s.summary
|
26
|
+
s.author = AUTHOR
|
27
|
+
s.email = EMAIL
|
28
|
+
s.homepage = HOMEPAGE
|
29
|
+
s.add_dependency("merb-slices", Merb::VERSION)
|
30
|
+
s.add_dependency("merb_datamapper", Merb::VERSION)
|
31
|
+
s.add_dependency("dm-core", ">= 0.9.11")
|
32
|
+
s.add_dependency("dm-is-paginated", ">= 0.0.1")
|
33
|
+
s.require_path = "lib"
|
34
|
+
s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
|
35
|
+
s.post_install_message = <<-POST_INSTALL_MESSAGE
|
36
|
+
#{"*" * 80}
|
37
|
+
|
38
|
+
WARNING: MerbAdmin does not implement any authorization scheme.
|
39
|
+
Make sure to apply authorization logic before deploying to production!
|
40
|
+
|
41
|
+
#{"*" * 80}
|
42
|
+
POST_INSTALL_MESSAGE
|
43
|
+
end
|
44
|
+
|
45
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
46
|
+
pkg.gem_spec = spec
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Install the gem"
|
50
|
+
task :install do
|
51
|
+
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Uninstall the gem"
|
55
|
+
task :uninstall do
|
56
|
+
Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "Create a gemspec file"
|
60
|
+
task :gemspec do
|
61
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
62
|
+
file.puts spec.to_ruby
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
require "spec/rake/spectask"
|
67
|
+
require "merb-core/test/tasks/spectasks"
|
68
|
+
desc "Default: run spec examples"
|
69
|
+
task :default => "spec"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class MerbAdmin::Application < Merb::Controller
|
2
|
+
|
3
|
+
controller_for_slice
|
4
|
+
|
5
|
+
before :set_model, :exclude => "index"
|
6
|
+
|
7
|
+
def set_model
|
8
|
+
@model_name = params[:model_name].to_s.camel_case.singularize
|
9
|
+
begin
|
10
|
+
@model = eval(@model_name)
|
11
|
+
rescue StandardError
|
12
|
+
raise NotFound
|
13
|
+
end
|
14
|
+
@properties = @model.properties.to_a
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class MerbAdmin::Forms < MerbAdmin::Application
|
2
|
+
layout :form
|
3
|
+
|
4
|
+
def index
|
5
|
+
@models = DataMapper::Resource.descendants.to_a.sort{|a, b| a.to_s <=> b.to_s}
|
6
|
+
# remove DataMapperSessionStore because it's included by default
|
7
|
+
@models -= [Merb::DataMapperSessionStore] if Merb.const_defined?(:DataMapperSessionStore)
|
8
|
+
render(:layout => "dashboard")
|
9
|
+
end
|
10
|
+
|
11
|
+
def list
|
12
|
+
if params[:all]
|
13
|
+
@instances = @model.all(:limit => 200).reverse
|
14
|
+
else
|
15
|
+
# monkey patch pagination
|
16
|
+
@model.class_eval("is_paginated") unless @model.respond_to?(:paginated)
|
17
|
+
@current_page = (params[:page] || 1).to_i
|
18
|
+
@page_count, @instances = @model.paginated(:page => @current_page, :per_page => 100)
|
19
|
+
end
|
20
|
+
render(:layout => "list")
|
21
|
+
end
|
22
|
+
|
23
|
+
def new
|
24
|
+
@instance = @model.new
|
25
|
+
render(:layout => "form")
|
26
|
+
end
|
27
|
+
|
28
|
+
def edit(id)
|
29
|
+
@instance = @model.get(id)
|
30
|
+
raise NotFound unless @instance
|
31
|
+
render(:layout => "form")
|
32
|
+
end
|
33
|
+
|
34
|
+
def create
|
35
|
+
instance = eval("params[:#{@model_name.snake_case}]")
|
36
|
+
@instance = @model.new(instance)
|
37
|
+
if @instance.save
|
38
|
+
if params[:_continue]
|
39
|
+
redirect slice_url(:admin_edit, :model_name => @model_name.snake_case, :id => @instance.id), :message => {:notice => "#{@model_name} was successfully created"}
|
40
|
+
elsif params[:_add_another]
|
41
|
+
redirect slice_url(:admin_new, :model_name => @model_name.snake_case), :message => {:notice => "#{@model_name} was successfully created"}
|
42
|
+
else
|
43
|
+
redirect slice_url(:admin_list, :model_name => @model_name.snake_case), :message => {:notice => "#{@model_name} was successfully created"}
|
44
|
+
end
|
45
|
+
else
|
46
|
+
message[:error] = "#{@model_name} failed to be created"
|
47
|
+
render(:new, :layout => "form")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def update(id)
|
52
|
+
instance = eval("params[:#{@model_name.snake_case}]")
|
53
|
+
@instance = @model.get(id)
|
54
|
+
raise NotFound unless @instance
|
55
|
+
if @instance.update_attributes(instance)
|
56
|
+
if params[:_continue]
|
57
|
+
redirect slice_url(:admin_edit, :model_name => @model_name.snake_case, :id => @instance.id), :message => {:notice => "#{@model_name} was successfully updated"}
|
58
|
+
elsif params[:_add_another]
|
59
|
+
redirect slice_url(:admin_new, :model_name => @model_name.snake_case), :message => {:notice => "#{@model_name} was successfully updated"}
|
60
|
+
else
|
61
|
+
redirect slice_url(:admin_list, :model_name => @model_name.snake_case), :message => {:notice => "#{@model_name} was successfully updated"}
|
62
|
+
end
|
63
|
+
else
|
64
|
+
message[:error] = "#{@model_name} failed to be updated"
|
65
|
+
render(:edit, :layout => "form")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete(id)
|
70
|
+
@instance = @model.get(id)
|
71
|
+
raise NotFound unless @instance
|
72
|
+
render(:layout => "form")
|
73
|
+
end
|
74
|
+
|
75
|
+
def destroy(id)
|
76
|
+
@instance = @model.get(id)
|
77
|
+
raise NotFound unless @instance
|
78
|
+
if @instance.destroy
|
79
|
+
redirect slice_url(:admin_list, :model_name => @model_name.snake_case), :message => {:notice => "#{@model_name} was successfully destroyed"}
|
80
|
+
else
|
81
|
+
raise InternalServerError
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Merb
|
2
|
+
module MerbAdmin
|
3
|
+
module ApplicationHelper
|
4
|
+
|
5
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
6
|
+
#
|
7
|
+
# @return <String>
|
8
|
+
# A path relative to the public directory, with added segments.
|
9
|
+
def image_path(*segments)
|
10
|
+
public_path_for(:image, *segments)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
14
|
+
#
|
15
|
+
# @return <String>
|
16
|
+
# A path relative to the public directory, with added segments.
|
17
|
+
def javascript_path(*segments)
|
18
|
+
public_path_for(:javascript, *segments)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
22
|
+
#
|
23
|
+
# @return <String>
|
24
|
+
# A path relative to the public directory, with added segments.
|
25
|
+
def stylesheet_path(*segments)
|
26
|
+
public_path_for(:stylesheet, *segments)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Construct a path relative to the public directory
|
30
|
+
#
|
31
|
+
# @param <Symbol> The type of component.
|
32
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
33
|
+
#
|
34
|
+
# @return <String>
|
35
|
+
# A path relative to the public directory, with added segments.
|
36
|
+
def public_path_for(type, *segments)
|
37
|
+
::MerbAdmin.public_path_for(type, *segments)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Construct an app-level path.
|
41
|
+
#
|
42
|
+
# @param <Symbol> The type of component.
|
43
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
44
|
+
#
|
45
|
+
# @return <String>
|
46
|
+
# A path within the host application, with added segments.
|
47
|
+
def app_path_for(type, *segments)
|
48
|
+
::MerbAdmin.app_path_for(type, *segments)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Construct a slice-level path.
|
52
|
+
#
|
53
|
+
# @param <Symbol> The type of component.
|
54
|
+
# @param *segments<Array[#to_s]> Path segments to append.
|
55
|
+
#
|
56
|
+
# @return <String>
|
57
|
+
# A path within the slice source (Gem), with added segments.
|
58
|
+
def slice_path_for(type, *segments)
|
59
|
+
::MerbAdmin.slice_path_for(type, *segments)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'builder'
|
2
|
+
module Merb
|
3
|
+
module MerbAdmin
|
4
|
+
module FormsHelper
|
5
|
+
# Given a page count and the current page, we generate a set of pagination
|
6
|
+
# links.
|
7
|
+
#
|
8
|
+
# * We use an inner and outer window into a list of links. For a set of
|
9
|
+
# 20 pages with the current page being 10:
|
10
|
+
# outer_window:
|
11
|
+
# 1 2 ..... 19 20
|
12
|
+
# inner_window
|
13
|
+
# 5 6 7 8 9 10 11 12 13 14
|
14
|
+
#
|
15
|
+
# This is totally adjustable, or can be turned off by giving the
|
16
|
+
# :inner_window setting a value of nil.
|
17
|
+
#
|
18
|
+
# * Options
|
19
|
+
# :left_cut_label => <em>text_for_cut</em>::
|
20
|
+
# Used when the page numbers need to be cut off to prevent the set of
|
21
|
+
# pagination links from being too long.
|
22
|
+
# Defaults to '…'
|
23
|
+
# :right_cut_label => <em>text_for_cut</em>::
|
24
|
+
# Same as :left_cut_label but for the right side of numbers.
|
25
|
+
# Defaults to '…'
|
26
|
+
# :outer_window => <em>number_of_pages</em>::
|
27
|
+
# Sets the number of pages to include in the outer 'window'
|
28
|
+
# Defaults to 2
|
29
|
+
# :inner_window => <em>number_of_pages</em>::
|
30
|
+
# Sets the number of pags to include in the inner 'window'
|
31
|
+
# Defaults to 7
|
32
|
+
# :page_param => <em>name_of_page_paramiter</em>
|
33
|
+
# Sets the name of the paramiter the paginator uses to return what
|
34
|
+
# page is being requested.
|
35
|
+
# Defaults to 'page'
|
36
|
+
# :url => <em>url_for_links</em>
|
37
|
+
# Provides the base url to use in the page navigation links.
|
38
|
+
# Defaults to ''
|
39
|
+
def paginate(current_page, page_count, options = {})
|
40
|
+
options.reverse_merge!({
|
41
|
+
:left_cut_label => '…',
|
42
|
+
:right_cut_label => '…',
|
43
|
+
:outer_window => 2,
|
44
|
+
:inner_window => 7,
|
45
|
+
:page_param => 'page',
|
46
|
+
:url => ''
|
47
|
+
})
|
48
|
+
url = options.delete :url
|
49
|
+
url << (url.include?('?') ? '&' : '?') << options[:page_param]
|
50
|
+
|
51
|
+
pages = {
|
52
|
+
:all => (1..page_count).to_a,
|
53
|
+
:left => [],
|
54
|
+
:center => [],
|
55
|
+
:right => []
|
56
|
+
}
|
57
|
+
|
58
|
+
# Only worry about using our 'windows' if the page count is less then
|
59
|
+
# our windows combined.
|
60
|
+
if options[:inner_window].nil? || ((options[:outer_window] * 2) + options[:inner_window] + 2) >= page_count
|
61
|
+
pages[:center] = pages[:all]
|
62
|
+
else
|
63
|
+
pages[:left] = pages[:all][0, options[:outer_window]]
|
64
|
+
pages[:right] = pages[:all][page_count - options[:outer_window], options[:outer_window]]
|
65
|
+
pages[:center] = case current_page
|
66
|
+
# allow the inner 'window' to shift to right when close to the left edge
|
67
|
+
# Ex: 1 2 [3] 4 5 6 7 8 9 ... 20
|
68
|
+
when -infinity .. (options[:inner_window] / 2) + 3
|
69
|
+
pages[:all][options[:outer_window], options[:inner_window]] +
|
70
|
+
[options[:right_cut_label]]
|
71
|
+
# allow the inner 'window' to shift left when close to the right edge
|
72
|
+
# Ex: 1 2 ... 12 13 14 15 16 [17] 18 19 20
|
73
|
+
when (page_count - (options[:inner_window] / 2.0).ceil) - 1 .. infinity
|
74
|
+
[options[:left_cut_label]] +
|
75
|
+
pages[:all][page_count - options[:inner_window] - options[:outer_window], options[:inner_window]]
|
76
|
+
# Display the unshifed window
|
77
|
+
# ex: 1 2 ... 5 6 7 [8] 9 10 11 ... 19 20
|
78
|
+
else
|
79
|
+
[options[:left_cut_label]] +
|
80
|
+
pages[:all][current_page - (options[:inner_window] / 2) - 1, options[:inner_window]] +
|
81
|
+
[options[:right_cut_label]]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
b = []
|
86
|
+
|
87
|
+
[pages[:left], pages[:center], pages[:right]].each do |p|
|
88
|
+
p.each do |page_number|
|
89
|
+
case page_number
|
90
|
+
when String
|
91
|
+
b << page_number
|
92
|
+
when current_page
|
93
|
+
b << Builder::XmlMarkup.new.span(page_number, :class => "this-page")
|
94
|
+
when page_count
|
95
|
+
b << Builder::XmlMarkup.new.a(page_number, :class => "end", :href => "#{url}=#{page_number}")
|
96
|
+
else
|
97
|
+
b << Builder::XmlMarkup.new.a(page_number, :href => "#{url}=#{page_number}")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
b.join(" ")
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def infinity
|
108
|
+
1.0 / 0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<%= text_field(property.name, :maxlength => property.length, :label => property.field.capitalize.gsub('_', ' ')) %>
|
4
|
+
<p class="help">
|
5
|
+
<%= !property.nullable? || property.serial? ? "Required." : "Optional." %>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<%= text_field(property.name, :class => "vDateField", :label => property.field.capitalize.gsub('_', ' '), :value => eval("@instance.#{property.field}").strftime("%Y-%m-%d")) %>
|
4
|
+
<p class="help">
|
5
|
+
<%= !property.nullable? ? "Required." : "Optional." %>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<%= text_field(property.name, :class => "vDateField", :label => property.field.capitalize.gsub('_', ' '), :value => eval("@instance.#{property.field}").strftime("%Y-%m-%d %H:%M:%S")) %>
|
4
|
+
<p class="help">
|
5
|
+
<%= !property.nullable? ? "Required." : "Optional." %>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<%= text_field(property.name, :maxlength => property.length, :label => property.field.capitalize.gsub('_', ' ')) %>
|
4
|
+
<p class="help">
|
5
|
+
<%= !property.nullable? || property.serial? ? "Required." : "Optional." %>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<% if property.type.respond_to?(:flag_map) #Enum or Flag type %>
|
4
|
+
<%= select(property.name, :collection => property.type.flag_map.map{|x| [x[1], x[1].to_s.capitalize.gsub('_', ' ')]}.sort{|a, b| a[1] <=> b[1]}, :label => property.field.capitalize.gsub('_', ' ')) %>
|
5
|
+
<% else %>
|
6
|
+
<%= text_field(property.name, :maxlength => property.length, :label => property.field.capitalize.gsub('_', ' ')) %>
|
7
|
+
<% end %>
|
8
|
+
<p class="help">
|
9
|
+
<%= !property.nullable? || property.serial? ? "Required." : "Optional." %>
|
10
|
+
</p>
|
11
|
+
</div>
|
12
|
+
</div>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<% case property.type.to_s %>
|
4
|
+
<% when "DataMapper::Types::Text" %>
|
5
|
+
<%= text_area(property.name, :cols => 80, :label => property.field.capitalize.gsub('_', ' ')) %>
|
6
|
+
<p class="help">
|
7
|
+
<%= property.nullable? ? "Required." : "Optional." %>
|
8
|
+
</p>
|
9
|
+
<% else %>
|
10
|
+
<%= text_field(property.name, :size => [50, property.length].min, :maxlength => property.length, :label => property.field.capitalize.gsub('_', ' ')) %>
|
11
|
+
<p class="help">
|
12
|
+
<%= !property.nullable? ? "Required." : "Optional." %> <%= property.length %> <%= property.length == 1 ? "character." : "characters or fewer." %>
|
13
|
+
</p>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<div class="form-row page">
|
2
|
+
<div>
|
3
|
+
<%= text_field(property.name, :class => "vTimeField", :label => property.field.capitalize.gsub('_', ' '), :value => eval("@instance.#{property.field}").strftime("%H:%M:%S")) %>
|
4
|
+
<p class="help">
|
5
|
+
<%= !property.nullable? ? "Required." : "Optional." %>
|
6
|
+
</p>
|
7
|
+
</div>
|
8
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<p>Are you sure you want to delete the <%= @model_name.snake_case.gsub('_', ' ') %>? All of the following related items will be deleted:</p>
|
2
|
+
<ul>
|
3
|
+
<li>
|
4
|
+
<a href="<%= slice_url(:admin_edit, :model_name => @model_name.snake_case, :id => @instance.id) %>"><%= @model_name %></a>
|
5
|
+
</li>
|
6
|
+
</ul>
|
7
|
+
<%= form_for(@instance, :action => slice_url(:admin_destroy, :model_name => @model_name.snake_case, :id => @instance.id), :method => :delete) do %>
|
8
|
+
<div>
|
9
|
+
<%= submit "Yes, I'm sure" %>
|
10
|
+
</div>
|
11
|
+
<% end =%>
|
12
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<div id="content-main">
|
2
|
+
<ul class="object-tools">
|
3
|
+
<li><a href="<%= "/#{@model_name.snake_case}/#{@instance.id}" %>" target="_blank" class="viewsitelink">View on site</a></li>
|
4
|
+
</ul>
|
5
|
+
<%= form_for(@instance, :action => slice_url(:admin_update, :model_name => @model_name.snake_case, :id => @instance.id)) do %>
|
6
|
+
<div>
|
7
|
+
<fieldset class="module aligned">
|
8
|
+
<h2><%= @model_name %> info</h2>
|
9
|
+
<% @properties.each do |property| %>
|
10
|
+
<% next if [:id, :created_at, :created_on, :updated_at, :updated_on].include?(property.name) %>
|
11
|
+
<%= partial property.primitive.to_s.snake_case, :property => property -%>
|
12
|
+
<% end %>
|
13
|
+
</fieldset>
|
14
|
+
<div class="submit-row" >
|
15
|
+
<%= submit "Save", :class => "default", :name => "_save" %>
|
16
|
+
<p class="deletelink-box"><a href="<%= slice_url(:admin_delete, :model_name => @model_name.snake_case, :id => @instance.id) %>" class="deletelink">Delete</a></p>
|
17
|
+
<%= submit "Save and add another", :name => "_add_another" %>
|
18
|
+
<%= submit "Save and continue editing", :name => "_continue" %>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
<% end =%>
|
22
|
+
|
23
|
+
</div>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<div id="content-main">
|
2
|
+
<div class="module">
|
3
|
+
<table summary="Models available in the application.">
|
4
|
+
<caption><a href="<%= slice_url(:admin_dashboard) %>" class="section">Models</a></caption>
|
5
|
+
<% @models.map{|m| m.to_s}.each do |model_name| %>
|
6
|
+
<tr>
|
7
|
+
<th scope="row"><a href="<%= slice_url(:admin_list, :model_name => model_name.snake_case) %>"><%=h model_name.pluralize %></a></th>
|
8
|
+
<td><a href="<%= slice_url(:admin_new, :model_name => model_name.snake_case) %>" class="addlink">Add</a></td>
|
9
|
+
<td><a href="<%= slice_url(:admin_list, :model_name => model_name.snake_case) %>" class="changelink">Edit</a></td>
|
10
|
+
</tr>
|
11
|
+
<% end %>
|
12
|
+
</table>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<div id="content-related">
|
16
|
+
<div class="module" id="recent-actions-module">
|
17
|
+
<h2>Recent Actions</h2>
|
18
|
+
<h3>My Actions</h3>
|
19
|
+
<p>None available</p>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
<br class="clear" />
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<div id="content-main">
|
2
|
+
<ul class="object-tools">
|
3
|
+
<li>
|
4
|
+
<a href="<%= slice_url(:admin_new, :model_name => @model_name.snake_case) %>" class="addlink">Add <%=h @model_name.snake_case.gsub('_', ' ') %></a>
|
5
|
+
</li>
|
6
|
+
</ul>
|
7
|
+
<div class="module filtered" id="changelist">
|
8
|
+
<table cellspacing="0">
|
9
|
+
<thead>
|
10
|
+
<tr>
|
11
|
+
<% @properties.each do |property| %>
|
12
|
+
<th>
|
13
|
+
<%= property.field.capitalize.gsub('_', ' ') %>
|
14
|
+
</th>
|
15
|
+
<% end %>
|
16
|
+
</tr>
|
17
|
+
</thead>
|
18
|
+
<tbody>
|
19
|
+
<% @instances.each_with_index do |instance, index| %>
|
20
|
+
<tr class="row<%= index % 2 == 0 ? '1' : '2' %>">
|
21
|
+
<% @properties.each do |property| %>
|
22
|
+
<td>
|
23
|
+
<a href="<%= slice_url(:admin_edit, :model_name => @model_name.snake_case, :id => eval("instance.id")) %>">
|
24
|
+
<% case property.primitive.to_s %>
|
25
|
+
<% when "TrueClass" %>
|
26
|
+
<% if eval("instance.#{property.field}") == true %>
|
27
|
+
<img alt="True" src="<%= image_path("icon-yes.gif") %>"/>
|
28
|
+
<% else %>
|
29
|
+
<img alt="False" src="<%= image_path("icon-no.gif") %>"/>
|
30
|
+
<% end %>
|
31
|
+
<% when "DateTime" %>
|
32
|
+
<%= eval("instance.#{property.field}").strftime("%b. %d, %Y, %I:%M%p") %>
|
33
|
+
<% when "Date" %>
|
34
|
+
<%= eval("instance.#{property.field}").strftime("%b. %d, %Y") %>
|
35
|
+
<% when "Time" %>
|
36
|
+
<%= eval("instance.#{property.field}").strftime("%I:%M%p") %>
|
37
|
+
<% when "Integer" %>
|
38
|
+
<% if property.type.respond_to?(:flag_map) #Enum or Flag type %>
|
39
|
+
<%= eval("instance.#{property.field}").to_s.capitalize.gsub('_', ' ') %>
|
40
|
+
<% else %>
|
41
|
+
<%= eval("instance.#{property.field}") %>
|
42
|
+
<% end %>
|
43
|
+
<% when "BigDecimal" %>
|
44
|
+
<%= eval("instance.#{property.field}") %>
|
45
|
+
<% when "Float" %>
|
46
|
+
<%= eval("instance.#{property.field}") %>
|
47
|
+
<% when "String" %>
|
48
|
+
<%= eval("instance.#{property.field}").to_s.truncate(50) %>
|
49
|
+
<% end %>
|
50
|
+
</a>
|
51
|
+
</td>
|
52
|
+
<% end %>
|
53
|
+
</tr>
|
54
|
+
<% end %>
|
55
|
+
</tbody>
|
56
|
+
</table>
|
57
|
+
<p class="paginator">
|
58
|
+
<%= paginate(@current_page, @page_count, :url => slice_url(:admin_list, :model_name => @model_name.snake_case)) if @page_count.to_i > 1 %>
|
59
|
+
<%= @model.count %> <%= @model.count == 1 ? @model_name.snake_case.gsub('_', ' ') : @model_name.snake_case.gsub('_', ' ').pluralize %>
|
60
|
+
<%= "<a href=\"#{slice_url(:admin_list, :model_name => @model_name.snake_case, :all => true)}\" class=\"showall\">Show all</a>" if @page_count.to_i == 2 %>
|
61
|
+
</p>
|
62
|
+
</div>
|
63
|
+
</div>
|
64
|
+
<br class="clear" />
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<div id="content-main">
|
2
|
+
<%= form_for(@instance, :action => slice_url(:admin_create, :model_name => @model_name.snake_case)) do %>
|
3
|
+
<div>
|
4
|
+
<fieldset class="module aligned">
|
5
|
+
<h2><%= @model_name %> info</h2>
|
6
|
+
<% @properties.each do |property| %>
|
7
|
+
<% next if [:id, :created_at, :created_on, :updated_at, :updated_on].include?(property.name) %>
|
8
|
+
<%= partial property.primitive.to_s.snake_case, :property => property -%>
|
9
|
+
<% end %>
|
10
|
+
</fieldset>
|
11
|
+
<div class="submit-row" >
|
12
|
+
<%= submit "Save", :class => "default", :name => "_save" %>
|
13
|
+
<%= submit "Save and add another", :name => "_add_another" %>
|
14
|
+
<%= submit "Save and continue editing", :name => "_continue" %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
<% end =%>
|
18
|
+
|
19
|
+
</div>
|