populate-me 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +655 -0
- data/Rakefile +14 -0
- data/example/config.ru +100 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +157 -0
- data/lib/populate_me/admin/__assets__/css/asmselect.css +63 -0
- data/lib/populate_me/admin/__assets__/css/jquery-ui.min.css +6 -0
- data/lib/populate_me/admin/__assets__/css/main.css +244 -0
- data/lib/populate_me/admin/__assets__/img/help/children.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/create.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/delete.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/edit.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/form.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/list.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/login.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/logout.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/menu.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/overview.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/save.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/sort.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/sublist.png +0 -0
- data/lib/populate_me/admin/__assets__/js/asmselect.js +412 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +87 -0
- data/lib/populate_me/admin/__assets__/js/jquery-ui.min.js +7 -0
- data/lib/populate_me/admin/__assets__/js/main.js +388 -0
- data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
- data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
- data/lib/populate_me/admin/views/help.erb +94 -0
- data/lib/populate_me/admin/views/page.erb +189 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +186 -0
- data/lib/populate_me/document.rb +192 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +149 -0
- data/lib/populate_me/document_mixins/callbacks.rb +125 -0
- data/lib/populate_me/document_mixins/outcasting.rb +83 -0
- data/lib/populate_me/document_mixins/persistence.rb +95 -0
- data/lib/populate_me/document_mixins/schema.rb +198 -0
- data/lib/populate_me/document_mixins/typecasting.rb +70 -0
- data/lib/populate_me/document_mixins/validation.rb +44 -0
- data/lib/populate_me/file_system_attachment.rb +40 -0
- data/lib/populate_me/grid_fs_attachment.rb +103 -0
- data/lib/populate_me/mongo.rb +160 -0
- data/lib/populate_me/s3_attachment.rb +120 -0
- data/lib/populate_me/variation.rb +38 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +34 -0
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +183 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +167 -0
- data/test/test_document.rb +128 -0
- data/test/test_document_admin_adapter.rb +221 -0
- data/test/test_document_callbacks.rb +151 -0
- data/test/test_document_outcasting.rb +247 -0
- data/test/test_document_persistence.rb +83 -0
- data/test/test_document_schema.rb +280 -0
- data/test/test_document_typecasting.rb +128 -0
- data/test/test_grid_fs_attachment.rb +239 -0
- data/test/test_mongo.rb +324 -0
- data/test/test_s3_attachment.rb +281 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +294 -0
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
task :default => :test
|
4
|
+
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
t.libs << "test"
|
7
|
+
t.pattern = 'test/test_*.rb'
|
8
|
+
unless ENV['TESTONLY'].nil?
|
9
|
+
t.pattern = t.pattern.sub(/\*/, ENV['TESTONLY'])
|
10
|
+
end
|
11
|
+
t.options = '--pride'
|
12
|
+
t.warning = false
|
13
|
+
end
|
14
|
+
|
data/example/config.ru
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# We use this example for running real tests on top of unit tests.
|
2
|
+
# This is not meant to be an example to learn how PopulateMe would work.
|
3
|
+
# Real examples will come later and this file will be removed.
|
4
|
+
|
5
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
6
|
+
|
7
|
+
# Models ##########
|
8
|
+
|
9
|
+
require 'populate_me/document'
|
10
|
+
|
11
|
+
# MONGO = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'blog-populate-me-test')
|
12
|
+
# DB = MONGO.database
|
13
|
+
# PopulateMe::Mongo.set :db, DB
|
14
|
+
|
15
|
+
require 'populate_me/attachment'
|
16
|
+
PopulateMe::Document.set :default_attachment_class, PopulateMe::Attachment
|
17
|
+
# require 'populate_me/file_system_attachment'
|
18
|
+
# PopulateMe::Document.set :default_attachment_class, PopulateMe::FileSystemAttachment
|
19
|
+
#
|
20
|
+
# require 'populate_me/grid_fs_attachment'
|
21
|
+
# PopulateMe::Mongo.set :default_attachment_class, PopulateMe::GridFS
|
22
|
+
# PopulateMe::GridFS.set :db, DB
|
23
|
+
|
24
|
+
# require 'populate_me/s3_attachment'
|
25
|
+
# s3_resource = Aws::S3::Resource.new
|
26
|
+
# s3_bucket = s3_resource.bucket(ENV['BUCKET'])
|
27
|
+
# PopulateMe::Document.set :default_attachment_class, PopulateMe::S3Attachment
|
28
|
+
# PopulateMe::S3Attachment.set :bucket, s3_bucket
|
29
|
+
|
30
|
+
|
31
|
+
class BlogPost < PopulateMe::Document
|
32
|
+
field :title, required: true
|
33
|
+
field :thumbnail, type: :attachment, max_size: 600*1024, variations: [
|
34
|
+
PopulateMe::Variation.new_image_magick_job(:populate_me_thumb, :jpg, "-resize '400x225^' -gravity center -extent 400x225")
|
35
|
+
]
|
36
|
+
field :content, type: :text
|
37
|
+
field :authors, type: :list
|
38
|
+
field :published, type: :boolean
|
39
|
+
field :date_now, type: :date, input_attributes: {type: :date}
|
40
|
+
field :datetime_now, type: :datetime, input_attributes: {type: :datetime}
|
41
|
+
relationship :comments
|
42
|
+
def validate
|
43
|
+
error_on(:content,'Cannot be blank') if WebUtils.blank?(self.content)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
class BlogPost::Author < PopulateMe::Document
|
48
|
+
# nested
|
49
|
+
field :name
|
50
|
+
def validate
|
51
|
+
error_on(:name, 'Cannot be shit') if self.name=='shit'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
class BlogPost::Comment < PopulateMe::Document
|
55
|
+
# not nested
|
56
|
+
field :author, default: 'Anonymous'
|
57
|
+
field :content, type: :text
|
58
|
+
field :blog_post_id, type: :hidden
|
59
|
+
position_field scope: :blog_post_id
|
60
|
+
end
|
61
|
+
|
62
|
+
class Article < PopulateMe::Document
|
63
|
+
field :title
|
64
|
+
field :content, type: :text
|
65
|
+
field :yes_or_no, type: :select, select_options: [:yes,:no]
|
66
|
+
field :tags, type: :select, multiple: true, select_options: ['art','sport','science']
|
67
|
+
field :price, type: :price
|
68
|
+
position_field
|
69
|
+
|
70
|
+
relationship :sections
|
71
|
+
|
72
|
+
after :save do
|
73
|
+
puts self.inspect
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Article::Section < PopulateMe::Document
|
78
|
+
|
79
|
+
field :short, only_for: 'Nice Short'
|
80
|
+
field :long, only_for: 'Nice Long'
|
81
|
+
field :article_id, type: :hidden
|
82
|
+
position_field scope: :article_id
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
# Admin ##########
|
87
|
+
|
88
|
+
require "populate_me/admin"
|
89
|
+
class Admin < PopulateMe::Admin
|
90
|
+
set :menu, [
|
91
|
+
['Blog Posts', '/list/blog-post'],
|
92
|
+
['Articles', '/list/article'],
|
93
|
+
]
|
94
|
+
end
|
95
|
+
|
96
|
+
use PopulateMe::Attachment::Middleware
|
97
|
+
# use PopulateMe::FileSystemAttachment::Middleware
|
98
|
+
# use PopulateMe::GridFS::Middleware
|
99
|
+
run Admin
|
100
|
+
|
data/lib/populate_me.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'populate_me/api'
|
2
|
+
require 'json'
|
3
|
+
require 'tilt/erb'
|
4
|
+
begin
|
5
|
+
require "rack/cerberus"
|
6
|
+
rescue LoadError
|
7
|
+
puts "Cerberus not loaded."
|
8
|
+
end
|
9
|
+
|
10
|
+
class PopulateMe::Admin < Sinatra::Base
|
11
|
+
|
12
|
+
# Settings
|
13
|
+
set :app_file, nil # Need to be set when subclassed
|
14
|
+
set :show_exceptions, false
|
15
|
+
set :meta_title, 'Populate Me'
|
16
|
+
set :index_path, '/menu'
|
17
|
+
enable :cerberus
|
18
|
+
set :cerberus_active, Proc.new{
|
19
|
+
cerberus_available? &&
|
20
|
+
!!cerberus_pass &&
|
21
|
+
settings.cerberus?
|
22
|
+
}
|
23
|
+
set :logout_path, Proc.new{ settings.cerberus_active ? '/logout' : false }
|
24
|
+
|
25
|
+
# Load API helpers
|
26
|
+
helpers PopulateMe::API::Helpers
|
27
|
+
helpers do
|
28
|
+
|
29
|
+
def user_name
|
30
|
+
return 'Anonymous' if session.nil?||session[:populate_me_user].nil?
|
31
|
+
session[:populate_me_user]
|
32
|
+
end
|
33
|
+
|
34
|
+
def help_img desc, filename
|
35
|
+
"<img src='#{request.script_name}/__assets__/img/help/#{filename}' alt='#{desc}' />"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# Make all templates in admin/views accessible with their basename
|
41
|
+
Dir["#{File.expand_path('../admin/views',__FILE__)}/*.erb"].each do |f|
|
42
|
+
template File.basename(f,'.erb').to_sym do
|
43
|
+
File.read(f)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
before do
|
48
|
+
content_type :json
|
49
|
+
end
|
50
|
+
|
51
|
+
get '/?' do
|
52
|
+
content_type :html
|
53
|
+
erb :page, layout: false
|
54
|
+
end
|
55
|
+
|
56
|
+
get '/menu/?*?' do
|
57
|
+
page_title = 'Menu'
|
58
|
+
current_level = settings.menu.dup
|
59
|
+
levels = params[:splat][0].split('/')
|
60
|
+
levels.each do |l|
|
61
|
+
page_title, current_level = current_level.find{|item| slugify(item[0])==l}
|
62
|
+
end
|
63
|
+
items = current_level.map do |l|
|
64
|
+
href = l[1].is_a?(String) ? l[1] : "#{request.script_name}/menu#{levels.map{|level|'/'+level}.join}/#{slugify(l[0])}"
|
65
|
+
{ title: l[0], href: href, new_page: (not href.start_with?('/')) }
|
66
|
+
end
|
67
|
+
if request.path_info=='/menu'
|
68
|
+
items.push({title: '?', href: "#{request.script_name}/help", new_page: false})
|
69
|
+
end
|
70
|
+
{
|
71
|
+
template: 'template_menu',
|
72
|
+
page_title: page_title,
|
73
|
+
items: items
|
74
|
+
}.to_json
|
75
|
+
end
|
76
|
+
|
77
|
+
get '/list/:class_name' do
|
78
|
+
@model_class = resolve_model_class params[:class_name]
|
79
|
+
@model_class.to_admin_list(request: request, params: params).to_json
|
80
|
+
end
|
81
|
+
|
82
|
+
get '/form/?:class_name?/?:id?' do
|
83
|
+
@model_class = resolve_model_class params[:class_name]
|
84
|
+
if params[:id].nil?
|
85
|
+
@model_instance = @model_class.new.set_defaults
|
86
|
+
@model_instance.set_from_hash(params[:data], typecast: true) unless params[:data].nil?
|
87
|
+
else
|
88
|
+
@model_instance = resolve_model_instance @model_class, params[:id]
|
89
|
+
end
|
90
|
+
@model_instance.to_admin_form(
|
91
|
+
request: request,
|
92
|
+
params: params,
|
93
|
+
nested: params[:nested]=='true',
|
94
|
+
input_name_prefix: params[:input_name_prefix]
|
95
|
+
).to_json
|
96
|
+
end
|
97
|
+
|
98
|
+
get '/help' do
|
99
|
+
content_type :html
|
100
|
+
erb :help, layout: false
|
101
|
+
end
|
102
|
+
|
103
|
+
not_found do
|
104
|
+
response.headers['X-Cascade'] = 'pass'
|
105
|
+
{'success'=>false,'message'=>'Not Found'}.to_json
|
106
|
+
end
|
107
|
+
|
108
|
+
error do
|
109
|
+
puts
|
110
|
+
puts env['sinatra.error'].inspect
|
111
|
+
puts
|
112
|
+
{'success'=>false,'message'=>env['sinatra.error'].message}.to_json
|
113
|
+
end
|
114
|
+
|
115
|
+
class << self
|
116
|
+
|
117
|
+
def cerberus_pass
|
118
|
+
# Method = overridable = testable
|
119
|
+
ENV['CERBERUS_PASS']
|
120
|
+
end
|
121
|
+
def cerberus_available?
|
122
|
+
# Method = overridable = testable
|
123
|
+
Rack.const_defined?(:Cerberus)
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def setup_default_middleware builder
|
129
|
+
# Override the Sinatra method
|
130
|
+
super builder
|
131
|
+
setup_populate_me_middleware builder
|
132
|
+
end
|
133
|
+
|
134
|
+
def setup_populate_me_middleware builder
|
135
|
+
# Authentication
|
136
|
+
setup_cerberus builder
|
137
|
+
# Mount assets on /__assets__
|
138
|
+
builder.use Rack::Static, :urls=>['/__assets__'], :root=>File.expand_path('../admin',__FILE__)
|
139
|
+
# Mount the API on /api
|
140
|
+
builder.use Rack::Builder do
|
141
|
+
map('/api'){ run PopulateMe::API }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def setup_cerberus builder
|
146
|
+
return unless settings.cerberus_active
|
147
|
+
cerberus_settings = settings.cerberus==true ? {} : settings.cerberus
|
148
|
+
cerberus_settings[:session_key] = 'populate_me_user'
|
149
|
+
builder.use Rack::Cerberus, cerberus_settings do |user,pass,req|
|
150
|
+
pass==cerberus_pass
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
.asmContainer {
|
2
|
+
/* container that surrounds entire asmSelect widget */
|
3
|
+
}
|
4
|
+
|
5
|
+
.asmSelect {
|
6
|
+
/* the newly created regular 'select' */
|
7
|
+
display: inline;
|
8
|
+
}
|
9
|
+
|
10
|
+
.asmOptionDisabled {
|
11
|
+
/* disabled options in new select */
|
12
|
+
color: #999;
|
13
|
+
}
|
14
|
+
|
15
|
+
.asmHighlight {
|
16
|
+
/* the highlight span */
|
17
|
+
padding: 0;
|
18
|
+
margin: 0 0 0 1em;
|
19
|
+
}
|
20
|
+
|
21
|
+
.asmList {
|
22
|
+
/* html list that contains selected items */
|
23
|
+
margin: 0.25em 0 1em 0;
|
24
|
+
position: relative;
|
25
|
+
display: block;
|
26
|
+
padding-left: 0;
|
27
|
+
list-style: none;
|
28
|
+
}
|
29
|
+
|
30
|
+
.asmListItem {
|
31
|
+
/* li item from the html list above */
|
32
|
+
position: relative;
|
33
|
+
margin-left: 0;
|
34
|
+
padding-left: 0;
|
35
|
+
list-style: none;
|
36
|
+
background: #ddd;
|
37
|
+
border: 1px solid #bbb;
|
38
|
+
width: 100%;
|
39
|
+
margin: 0 0 -1px 0;
|
40
|
+
line-height: 1em;
|
41
|
+
}
|
42
|
+
|
43
|
+
.asmListItem:hover {
|
44
|
+
background-color: #e5e5e5;
|
45
|
+
}
|
46
|
+
|
47
|
+
.asmListItemLabel {
|
48
|
+
/* this is a span that surrounds the text in the item, except for the remove link */
|
49
|
+
padding: 5px;
|
50
|
+
display: block;
|
51
|
+
}
|
52
|
+
|
53
|
+
.asmListSortable .asmListItemLabel {
|
54
|
+
cursor: move;
|
55
|
+
}
|
56
|
+
|
57
|
+
.asmListItemRemove {
|
58
|
+
/* the remove link in each list item */
|
59
|
+
position: absolute;
|
60
|
+
right: 0;
|
61
|
+
top: 0;
|
62
|
+
padding: 5px;
|
63
|
+
}
|
@@ -0,0 +1,244 @@
|
|
1
|
+
/* General */
|
2
|
+
|
3
|
+
html, body {
|
4
|
+
margin: 0;
|
5
|
+
padding: 0;
|
6
|
+
color: #002b36;
|
7
|
+
background-color: #eee8d5;
|
8
|
+
height: 100%;
|
9
|
+
font-family: 'Avenir', sans-serif;
|
10
|
+
}
|
11
|
+
|
12
|
+
body {
|
13
|
+
line-height: 1.5em;
|
14
|
+
}
|
15
|
+
|
16
|
+
#finder {
|
17
|
+
height: 100%;
|
18
|
+
}
|
19
|
+
|
20
|
+
.column {
|
21
|
+
background: #fdf6e3;
|
22
|
+
height: 100%;
|
23
|
+
min-width: 250px;
|
24
|
+
overflow: auto;
|
25
|
+
box-shadow: 0px 0px 10px #586e75;
|
26
|
+
}
|
27
|
+
|
28
|
+
.column > h1, .column > ol,
|
29
|
+
.column > form, .column > p { /* Column padding */
|
30
|
+
margin-left: 20px;
|
31
|
+
margin-right: 20px;
|
32
|
+
}
|
33
|
+
|
34
|
+
.column > h1,
|
35
|
+
.column > .text-page h1 {
|
36
|
+
font-size: 1.5em;
|
37
|
+
font-weight: normal;
|
38
|
+
margin-top: 1em;
|
39
|
+
margin-bottom: 1.5em;
|
40
|
+
}
|
41
|
+
|
42
|
+
.column > .text-page {
|
43
|
+
padding: 0 20px 20px 20px;
|
44
|
+
overflow: hidden;
|
45
|
+
width: 50%; width: 50vw;
|
46
|
+
max-width: 600px;
|
47
|
+
background-color: #ffffff;
|
48
|
+
}
|
49
|
+
.column > .text-page h2 {
|
50
|
+
font-size: 1.5em;
|
51
|
+
}
|
52
|
+
.column > .text-page img {
|
53
|
+
width: 100%;
|
54
|
+
}
|
55
|
+
.column > .text-page a {
|
56
|
+
color: #268bd2;
|
57
|
+
}
|
58
|
+
.column > .text-page a:hover {
|
59
|
+
text-decoration: underline;
|
60
|
+
}
|
61
|
+
.column > .text-page .frame {
|
62
|
+
padding: 1em;
|
63
|
+
border: 1px solid #002b36;
|
64
|
+
}
|
65
|
+
|
66
|
+
ol {
|
67
|
+
list-style: none;
|
68
|
+
margin: 0;
|
69
|
+
padding: 0;
|
70
|
+
}
|
71
|
+
|
72
|
+
a {
|
73
|
+
color: #002b36;
|
74
|
+
text-decoration: none;
|
75
|
+
/* border-bottom: 1px solid #002b36; */
|
76
|
+
}
|
77
|
+
a:hover, a.selected {
|
78
|
+
/* Blue */
|
79
|
+
color: #268bd2;
|
80
|
+
/* Green/Blue */
|
81
|
+
/* color: #2aa198; */
|
82
|
+
}
|
83
|
+
|
84
|
+
button { cursor: pointer; }
|
85
|
+
|
86
|
+
/* Lists */
|
87
|
+
|
88
|
+
.new-document-btn-wrap > * {
|
89
|
+
vertical-align: middle;
|
90
|
+
}
|
91
|
+
|
92
|
+
.new-document-btn, .new-nested-document-btn {
|
93
|
+
border: 0;
|
94
|
+
font-size: 1.615em;
|
95
|
+
margin-bottom: 1em;
|
96
|
+
}
|
97
|
+
|
98
|
+
button.admin-delete, button.admin-delete-nested, .handle-button {
|
99
|
+
display: inline-block; vertical-align: middle;
|
100
|
+
font-size: 1em; line-height: 1em;
|
101
|
+
width: auto; height: auto;
|
102
|
+
margin: 0;
|
103
|
+
padding: 0.5em 0.5em 0.5em 0;
|
104
|
+
border: 0px;
|
105
|
+
}
|
106
|
+
button.admin-delete, button.admin-delete-nested {
|
107
|
+
color: #dc322f;
|
108
|
+
background-color: transparent;
|
109
|
+
}
|
110
|
+
button.admin-delete:focus, button.admin-delete-nested:focus, .handle-button:focus {
|
111
|
+
outline: 0;
|
112
|
+
}
|
113
|
+
.handle {
|
114
|
+
cursor: move;
|
115
|
+
cursor: -moz-grab;
|
116
|
+
cursor: -webkit-grab;
|
117
|
+
cursor: grab;
|
118
|
+
}
|
119
|
+
.handle:active {
|
120
|
+
cursor: -moz-grabbing;
|
121
|
+
cursor: -webkit-grabbing;
|
122
|
+
cursor: grabbing;
|
123
|
+
}
|
124
|
+
|
125
|
+
[type=submit] {
|
126
|
+
border: 0px;
|
127
|
+
cursor: pointer;
|
128
|
+
color: #fdf6e3;
|
129
|
+
background-color: #859900;
|
130
|
+
}
|
131
|
+
[type=submit]:hover {
|
132
|
+
background-color: #268bd2;
|
133
|
+
}
|
134
|
+
|
135
|
+
.documents, .nested-documents {
|
136
|
+
-webkit-touch-callout: none;
|
137
|
+
-webkit-user-select: none;
|
138
|
+
-khtml-user-select: none;
|
139
|
+
-moz-user-select: none;
|
140
|
+
-ms-user-select: none;
|
141
|
+
user-select: none;
|
142
|
+
}
|
143
|
+
.documents.grid {
|
144
|
+
width: 90%; width: 90vw;
|
145
|
+
}
|
146
|
+
.documents > li, .nested-documents > li {
|
147
|
+
display: block;
|
148
|
+
margin-bottom: 1em;
|
149
|
+
}
|
150
|
+
.documents.grid > li {
|
151
|
+
display: inline-block;
|
152
|
+
vertical-align: top;
|
153
|
+
width: 200px;
|
154
|
+
margin-right: 1em;
|
155
|
+
}
|
156
|
+
.documents.grid > li > a {
|
157
|
+
word-break: break-word;
|
158
|
+
}
|
159
|
+
.documents.grid > li img {
|
160
|
+
width: 200px;
|
161
|
+
}
|
162
|
+
.documents > li:hover, .nested-documents > li:hover {
|
163
|
+
background-color: #eee8d5;
|
164
|
+
outline: 0.5em solid #eee8d5;
|
165
|
+
}
|
166
|
+
.nested-documents > li > header {
|
167
|
+
background: #002b36;
|
168
|
+
height: 1.5em;
|
169
|
+
margin-bottom: 1em;
|
170
|
+
}
|
171
|
+
.documents .sortable-placeholder, .nested-documents .sortable-placeholder {
|
172
|
+
border: 1px dashed #839496;
|
173
|
+
background-color: #eee8d5;
|
174
|
+
}
|
175
|
+
.local-menu { font-size: 0.7em; }
|
176
|
+
|
177
|
+
/* Forms */
|
178
|
+
|
179
|
+
form {
|
180
|
+
margin-bottom: 2em;
|
181
|
+
}
|
182
|
+
|
183
|
+
.field {
|
184
|
+
margin-bottom: 1em;
|
185
|
+
}
|
186
|
+
|
187
|
+
input[type=text], input[type=email],
|
188
|
+
textarea {
|
189
|
+
border: 0px;
|
190
|
+
color: #839496;
|
191
|
+
background: #ffffff;
|
192
|
+
width: 400px;
|
193
|
+
padding: 0.5em;
|
194
|
+
font-size: 1em;
|
195
|
+
}
|
196
|
+
input[type=text]:focus, input[type=email]:focus,
|
197
|
+
textarea:focus {
|
198
|
+
/* color: #002b36; */
|
199
|
+
}
|
200
|
+
|
201
|
+
textarea { height: 6em; resize: vertical; }
|
202
|
+
textarea.oneline { height: 1em; resize: none; }
|
203
|
+
|
204
|
+
fieldset {
|
205
|
+
border: 0;
|
206
|
+
padding-left: 3em; padding-right: 0;
|
207
|
+
}
|
208
|
+
|
209
|
+
.invalid > label {
|
210
|
+
color: #dc322f;
|
211
|
+
}
|
212
|
+
|
213
|
+
/* asmSelect */
|
214
|
+
|
215
|
+
.asmListItem {
|
216
|
+
background-color: #ffffff;
|
217
|
+
border: 1px solid #fdf6e3;
|
218
|
+
}
|
219
|
+
.asmListItem:hover { background-color: #eee8d5; }
|
220
|
+
.asmListItemLabel { padding-right: 2em; }
|
221
|
+
.asmListSortable .asmListItemLabel {
|
222
|
+
cursor: move;
|
223
|
+
cursor: -moz-grab;
|
224
|
+
cursor: -webkit-grab;
|
225
|
+
cursor: grab;
|
226
|
+
}
|
227
|
+
.asmListSortable .asmListItemLabel:active {
|
228
|
+
cursor: -moz-grabbing;
|
229
|
+
cursor: -webkit-grabbing;
|
230
|
+
cursor: grabbing;
|
231
|
+
}
|
232
|
+
.asmListItemRemove, .asmListItemRemove:hover { color: #dc322f; }
|
233
|
+
|
234
|
+
|
235
|
+
/\
|
236
|
+
/ *\
|
237
|
+
/ # \
|
238
|
+
/ * \
|
239
|
+
/ # \
|
240
|
+
/ # * \
|
241
|
+
/ * # \
|
242
|
+
/______________\
|
243
|
+
|
244
|
+
|