forma 0.0.0 → 0.1.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.
- data/README.md +40 -0
- data/Rakefile +8 -0
- data/lib/forma/action.rb +45 -0
- data/lib/forma/config.rb +68 -0
- data/lib/forma/field.rb +451 -0
- data/lib/forma/form.rb +257 -0
- data/lib/forma/helpers.rb +139 -0
- data/lib/forma/html.rb +163 -2
- data/lib/forma/railtie.rb +15 -0
- data/lib/forma/table.rb +115 -0
- data/lib/forma/utils.rb +24 -0
- data/lib/forma/version.rb +1 -1
- data/lib/forma.rb +8 -0
- data/spec/config_spec.rb +20 -0
- data/spec/field_spec.rb +3 -0
- data/spec/form_spec.rb +33 -0
- data/spec/helpers_spec.rb +18 -0
- data/spec/html_spec.rb +26 -0
- data/spec/spec_helper.rb +0 -6
- data/test/field_test.rb +63 -0
- data/test/form_test.rb +16 -0
- data/test/test_helper.rb +3 -0
- data/vendor/assets/images/ff-icons.png +0 -0
- data/vendor/assets/javascripts/forma.js +147 -0
- data/vendor/assets/stylesheets/forma-min.css +41 -1
- data/vendor/assets/stylesheets/forma.css +326 -6
- data/vendor/less/forma.less +138 -8
- metadata +28 -9
- data/.rspec +0 -1
- data/lib/forma/html/attributes.rb +0 -104
- data/lib/forma/html/element.rb +0 -74
- data/spec/html/attributes_spec.rb +0 -54
- data/spec/html/element_spec.rb +0 -21
data/lib/forma/version.rb
CHANGED
data/lib/forma.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
require 'active_support/core_ext'
|
3
3
|
require 'forma/version'
|
4
|
+
require 'forma/utils'
|
4
5
|
require 'forma/html'
|
6
|
+
require 'forma/config'
|
7
|
+
require 'forma/helpers'
|
8
|
+
require 'forma/action'
|
9
|
+
require 'forma/form'
|
10
|
+
require 'forma/table'
|
11
|
+
require 'forma/field'
|
12
|
+
require 'forma/railtie' if defined?(Rails)
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe 'Number configuration' do
|
5
|
+
specify { Forma.config.num.delimiter.should == ',' }
|
6
|
+
specify { Forma.config.num.separator.should == '.' }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'Date configuration' do
|
10
|
+
specify { Forma.config.date.formatter.should == '%d-%b-%Y' }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'Texts configuration' do
|
14
|
+
specify { Forma.config.texts.empty.should == '(empty)' }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'Map configuration' do
|
18
|
+
specify { Forma.config.map.default_latitude == 41.711447 }
|
19
|
+
specify { Forma.config.map.default_longitude == 44.754514 }
|
20
|
+
end
|
data/spec/field_spec.rb
ADDED
data/spec/form_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
include Forma
|
5
|
+
|
6
|
+
# describe 'simple form' do
|
7
|
+
# before(:all) do
|
8
|
+
# @form = Form.new(
|
9
|
+
# id: 'user-login',
|
10
|
+
# title: 'User Login',
|
11
|
+
# collapsible: true,
|
12
|
+
# collapsed: false,
|
13
|
+
# icon: '/assets/user.png',
|
14
|
+
# edit: true,
|
15
|
+
# url: '/login',
|
16
|
+
# method: 'post',
|
17
|
+
# selected_tab: 0,
|
18
|
+
# tabs: [
|
19
|
+
# Tab.new(title: 'Login', icon: '/assets/user.png', col1: Col.new([
|
20
|
+
# TextField.new(name: 'username', label: 'Username', required: true),
|
21
|
+
# TextField.new(name: 'password', label: 'Password', required: true)
|
22
|
+
# ])),
|
23
|
+
# Tab.new(title: 'Reset password', icon: '/assets/password.png'),
|
24
|
+
# ]
|
25
|
+
# )
|
26
|
+
# @element = @form.to_html
|
27
|
+
# # puts Nokogiri::XML(@element.to_s, &:noblanks).to_xhtml(indent: 2)
|
28
|
+
# end
|
29
|
+
# specify { @element.tag.should == 'div' }
|
30
|
+
# specify { @element.id.should == 'user-login' }
|
31
|
+
# specify { @element.klass.should == [ 'ff-form' ] }
|
32
|
+
# # TODO: check other elements
|
33
|
+
# end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
include Forma::Helpers
|
4
|
+
|
5
|
+
# describe "forma helper" do
|
6
|
+
# before(:all) do
|
7
|
+
# @user_password = { username: 'dimitri', password: 'secret', age: 33, email: 'dimakura@gmail.com' }
|
8
|
+
# @forma = forma_for(@user_password) do |f|
|
9
|
+
# f.text_field :username
|
10
|
+
# f.password_field :password
|
11
|
+
# f.number_field :age
|
12
|
+
# f.email_field :email
|
13
|
+
# end
|
14
|
+
# # puts Nokogiri::XML(@forma, &:noblanks).to_xhtml(indent: 2)
|
15
|
+
# end
|
16
|
+
# specify { @forma.should_not be_nil }
|
17
|
+
# specify { @forma.should be_a String }
|
18
|
+
# end
|
data/spec/html_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
include Forma::Html
|
5
|
+
|
6
|
+
describe 'attribute helper method' do
|
7
|
+
specify { attr('id', 'forma4').to_s.should == 'id="forma4"' }
|
8
|
+
specify { attr('btn').to_s.should == 'class="btn"' }
|
9
|
+
specify { attr(['btn', 'btn-primary']).to_s.should == 'class="btn btn-primary"' }
|
10
|
+
specify { attr({'font-size' => '10px', 'font-weight' => 'bold'}).to_s.should == 'style="font-size:10px;font-weight:bold"' }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'element creation' do
|
14
|
+
specify { el('div').to_s.should == '<div></div>' }
|
15
|
+
specify { el('div', attrs: { id: 'forma4' }).to_s.should == '<div id="forma4"></div>' }
|
16
|
+
specify { el('div', attrs: { id: 'forma4', class: 'main' }).to_s.should == '<div id="forma4" class="main"></div>' }
|
17
|
+
specify { el('div', attrs: { id: 'forma4', class: ['main', 'very-important'], style: {'font-size' => '10px'} }).to_s.should == '<div id="forma4" class="main very-important" style="font-size:10px"></div>' }
|
18
|
+
specify { el('div', children: [el('div')]).to_s.should == '<div><div></div></div>' }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'element id' do
|
22
|
+
specify { el('div').id.should be_nil }
|
23
|
+
specify { el('div', attrs: { id: 'forma4' }).id.should == 'forma4' }
|
24
|
+
specify { el('div', attrs: { class: 'myform1' }).klass.should == [ 'myform1' ] }
|
25
|
+
specify { el('div', attrs: { class: ['myform1', 'myform2'] }).klass.should == [ 'myform1', 'myform2' ] }
|
26
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/test/field_test.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class FieldTest < Test::Unit::TestCase
|
5
|
+
include Forma
|
6
|
+
|
7
|
+
def test_general_field
|
8
|
+
fld = Field.new(model_name: 'user', name: 'first_name', value: 'fake value', label: 'First Name')
|
9
|
+
assert_equal 'user', fld.model_name
|
10
|
+
assert_equal 'first_name', fld.name
|
11
|
+
assert_equal 'models.user.first_name', fld.localization_key
|
12
|
+
assert_equal 'First Name', fld.label
|
13
|
+
assert_equal 'First Name', fld.localized_label
|
14
|
+
assert_equal nil, fld.hint
|
15
|
+
assert_equal '', fld.localized_hint
|
16
|
+
assert_equal 'fake value', fld.value
|
17
|
+
assert_equal 'user_first_name', fld.id
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_text_field
|
21
|
+
model = { first_name: 'Dimitri', last_name: 'Kurashvili' }
|
22
|
+
fld_first_name = TextField.new(model_name: 'user', name: 'first_name', model: model, hint: "user's first name")
|
23
|
+
fld_last_name = TextField.new(model_name: 'user', name: 'last_name', model: model)
|
24
|
+
assert_equal 'first_name', fld_first_name.name
|
25
|
+
assert_equal "user's first name", fld_first_name.hint
|
26
|
+
assert_equal "user's first name", fld_first_name.localized_hint
|
27
|
+
assert_equal 'Dimitri', fld_first_name.value
|
28
|
+
assert_equal 'last_name', fld_last_name.name
|
29
|
+
assert_equal 'user_first_name', fld_first_name.id
|
30
|
+
assert_equal 'user[first_name]', fld_first_name.parameter_name
|
31
|
+
assert_equal 'user_last_name', fld_last_name.id
|
32
|
+
assert_equal 'user[last_name]', fld_last_name.parameter_name
|
33
|
+
fld_first_name_ka = TextField.new(name: 'ka', parent: fld_first_name)
|
34
|
+
assert_equal 'user_first_name_ka', fld_first_name_ka.id
|
35
|
+
assert_equal 'user[first_name_attributes[ka]]', fld_first_name_ka.parameter_name
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_text_field_value_override
|
39
|
+
model = { first_name: 'Dimitri', last_name: 'Kurashvili' }
|
40
|
+
fld_first_name = TextField.new(model_name: 'user', name: 'first_name', model: model, value: 'other_name')
|
41
|
+
assert_equal 'other_name', fld_first_name.value
|
42
|
+
fld_first_name.value = nil
|
43
|
+
assert_equal 'Dimitri', fld_first_name.value
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_generated_text_field
|
47
|
+
model = { first_name: 'Dimitri', last_name: 'Kurashvili' }
|
48
|
+
fld_first_name = TextField.new(model_name: 'user', name: 'first_name', model: model)
|
49
|
+
el = fld_first_name.edit_element('Dimitri')
|
50
|
+
assert_equal 'input', el.tag
|
51
|
+
assert_equal 'user_first_name', el.attrs_by_name('id').first.value
|
52
|
+
assert_equal 'user[first_name]', el.attrs_by_name('name').first.value
|
53
|
+
assert_equal 'text', el.attrs_by_name('type').first.value
|
54
|
+
assert_equal 'Dimitri', el.attrs_by_name('value').first.value
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_compex_field
|
58
|
+
model = { first_name: 'Dimitri', last_name: 'Kurashvili' }
|
59
|
+
fld = ComplexField.new(fields: [ TextField.new(name: 'first_name'), TextField.new(name: 'last_name') ])
|
60
|
+
fld.model = model
|
61
|
+
assert_equal ['Dimitri', 'Kurashvili'], fld.value
|
62
|
+
end
|
63
|
+
end
|
data/test/form_test.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class FormTest < Test::Unit::TestCase
|
5
|
+
include Forma
|
6
|
+
|
7
|
+
def test_general_field
|
8
|
+
model = { first_name: 'Dimitri', last_name: 'Kurashvili' }
|
9
|
+
fld_first_name = TextField.new(model_name: 'user', name: 'first_name', model: model)
|
10
|
+
fld_last_name = TextField.new(model_name: 'user', name: 'last_name', model: model)
|
11
|
+
frm = Form.new
|
12
|
+
frm.add_field(fld_first_name)
|
13
|
+
frm.add_field(fld_last_name)
|
14
|
+
# puts frm.to_html
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
Binary file
|
@@ -0,0 +1,147 @@
|
|
1
|
+
(function() {
|
2
|
+
|
3
|
+
var initilizeCollapsibleElement = function() {
|
4
|
+
$('.ff-collapsible').click(function(evt) {
|
5
|
+
var activeTitle = $(this);
|
6
|
+
var formBody = $(activeTitle.parent().siblings('.ff-collapsible-body')[0]);
|
7
|
+
var collapseElement = $(activeTitle.children('.ff-collapse')[0]);
|
8
|
+
var isCollapsed = collapseElement.hasClass('ff-collapsed');
|
9
|
+
if (isCollapsed) {
|
10
|
+
formBody.show();
|
11
|
+
collapseElement.removeClass('ff-collapsed');
|
12
|
+
} else {
|
13
|
+
formBody.hide();
|
14
|
+
collapseElement.addClass('ff-collapsed');
|
15
|
+
}
|
16
|
+
});
|
17
|
+
};
|
18
|
+
|
19
|
+
var initializeTabs = function() {
|
20
|
+
$('.ff-tabs-header li').click(function(evnt) {
|
21
|
+
var newTab = $(this);
|
22
|
+
var oldTab = newTab.siblings('.ff-selected');
|
23
|
+
if (oldTab) {
|
24
|
+
var newIndex = newTab.parent().children().index(newTab);
|
25
|
+
var oldIndex = oldTab.parent().children().index(oldTab);
|
26
|
+
var newBody = $($(newTab.parent().parent().children()[1]).children()[newIndex]);
|
27
|
+
var oldBody = $($(newTab.parent().parent().children()[1]).children()[oldIndex]);
|
28
|
+
oldTab.removeClass("ff-selected");
|
29
|
+
oldBody.hide();
|
30
|
+
newTab.addClass("ff-selected");
|
31
|
+
newBody.show();
|
32
|
+
// we need to initialize a map
|
33
|
+
// if it was not visible and became
|
34
|
+
// visible when the tab was open
|
35
|
+
initGoogleMaps();
|
36
|
+
}
|
37
|
+
});
|
38
|
+
};
|
39
|
+
|
40
|
+
var initializeFormSubmit = function() {
|
41
|
+
$('form.ff-wait-on-submit').submit(function(evnt) {
|
42
|
+
var btn = $($(this).find('button[type=submit]')[0]);
|
43
|
+
btn.html(btn.html() + '...');
|
44
|
+
btn.attr('disabled', true);
|
45
|
+
return true;
|
46
|
+
});
|
47
|
+
};
|
48
|
+
|
49
|
+
var initializeTooltips = function() {
|
50
|
+
$('.ff-field-hint').tooltip({ placement: 'right', trigger: 'click' });
|
51
|
+
$('.ff-action').tooltip({ placement: 'top' });
|
52
|
+
// TODO: any other tooltips?
|
53
|
+
};
|
54
|
+
|
55
|
+
var initializeSelectFields = function() {
|
56
|
+
$('.ff-select-link').click(function() {
|
57
|
+
var link = $(this);
|
58
|
+
var url = link.attr('data-url');
|
59
|
+
var height = link.attr('data-height');
|
60
|
+
var width = link.attr('data-width');
|
61
|
+
var screenLeft = window.screenLeft;
|
62
|
+
var screenTop = window.screenTop;
|
63
|
+
var browserHeight = window.outerHeight;
|
64
|
+
var browserWidth = window.outerWidth;
|
65
|
+
var left = parseInt((screenLeft + browserWidth - width) / 2);
|
66
|
+
var top = parseInt((screenTop + browserHeight - height) / 2);
|
67
|
+
var properties = ['height=', height, ',width=', width, ',left=', left, ',top=', top];
|
68
|
+
window.open(url, link.attr('data-id'), properties.join(''));
|
69
|
+
});
|
70
|
+
};
|
71
|
+
|
72
|
+
// google map initialization
|
73
|
+
|
74
|
+
var mapsData = {};
|
75
|
+
|
76
|
+
var registerGoogleMap = function(id, zoom, center, coordinates, draggable) {
|
77
|
+
mapsData[id] = { id: id, zoom: zoom, center: center, coordinates: coordinates, draggable: draggable }
|
78
|
+
};
|
79
|
+
|
80
|
+
var getGoogleMap = function(id) {
|
81
|
+
return mapsData[id];
|
82
|
+
};
|
83
|
+
|
84
|
+
var googleMapInitialization = function(data) {
|
85
|
+
var id = data['id'];
|
86
|
+
if ($('#' + id).is(':visible')) {
|
87
|
+
var mapOptions = {
|
88
|
+
center: new google.maps.LatLng(data.center.latitude, data.center.longitude),
|
89
|
+
zoom: data.zoom,
|
90
|
+
mapTypeId: google.maps.MapTypeId.HYBRID //ROADMAP
|
91
|
+
};
|
92
|
+
var map = new google.maps.Map(document.getElementById(id), mapOptions);
|
93
|
+
var markers = [ ];
|
94
|
+
for (var i = 0, l = data.coordinates.length; i < l; i++) {
|
95
|
+
var markerData = data.coordinates[i];
|
96
|
+
var markerPosition = new google.maps.LatLng(markerData.latitude, markerData.longitude);
|
97
|
+
var marker = new google.maps.Marker({
|
98
|
+
position: markerPosition,
|
99
|
+
animation: google.maps.Animation.DROP,
|
100
|
+
map: map,
|
101
|
+
draggable: data.draggable,
|
102
|
+
});
|
103
|
+
markers.push(marker);
|
104
|
+
google.maps.event.addListener(marker, 'dragend', function() {
|
105
|
+
var pos = marker.getPosition();
|
106
|
+
$('#' + id + '_latitude').val(pos.lat() + '');
|
107
|
+
$('#' + id + '_longitude').val(pos.lng());
|
108
|
+
});
|
109
|
+
}
|
110
|
+
data.map = map;
|
111
|
+
data.markers = markers;
|
112
|
+
}
|
113
|
+
};
|
114
|
+
|
115
|
+
var initGoogleMaps = function() {
|
116
|
+
for (var id in mapsData) {
|
117
|
+
var data = mapsData[id];
|
118
|
+
if (data && !data.map) {
|
119
|
+
googleMapInitialization(data);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
};
|
123
|
+
|
124
|
+
// prepare function
|
125
|
+
|
126
|
+
var ready = function() {
|
127
|
+
initilizeCollapsibleElement();
|
128
|
+
initializeTabs();
|
129
|
+
initializeFormSubmit();
|
130
|
+
initializeTooltips();
|
131
|
+
initGoogleMaps();
|
132
|
+
initializeSelectFields();
|
133
|
+
};
|
134
|
+
|
135
|
+
// turbolink initilization!
|
136
|
+
// http://railscasts.com/episodes/390-turbolinks?view=asciicast
|
137
|
+
$(document).ready(ready);
|
138
|
+
$(document).on('page:load', ready);
|
139
|
+
|
140
|
+
// external API
|
141
|
+
|
142
|
+
window.forma = {
|
143
|
+
registerGoogleMap: registerGoogleMap,
|
144
|
+
getGoogleMap: getGoogleMap,
|
145
|
+
};
|
146
|
+
|
147
|
+
})();
|
@@ -1 +1,41 @@
|
|
1
|
-
.
|
1
|
+
.user-select-none{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;}
|
2
|
+
.ff-form,.ff-table{margin-bottom:16px;}.ff-form .ff-action,.ff-table .ff-action{margin-left:4px;}.ff-form .ff-action:first-child,.ff-table .ff-action:first-child{margin-left:0;}
|
3
|
+
.ff-form .ff-action img,.ff-table .ff-action img{padding-right:4px;height:16px;width:16px;}
|
4
|
+
.ff-form .ff-title,.ff-table .ff-title{position:relative;}.ff-form .ff-title .ff-active-title,.ff-table .ff-title .ff-active-title{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:pointer;display:inline-block;padding:4px 8px;font-weight:bold;font-size:14px;}.ff-form .ff-title .ff-active-title .ff-collapse,.ff-table .ff-title .ff-active-title .ff-collapse{display:inline-block;height:14px;width:14px;margin-right:4px;margin-top:2px;}
|
5
|
+
.ff-form .ff-title .ff-active-title img,.ff-table .ff-title .ff-active-title img{height:16px;width:16px;overflow:hidden;margin-right:4px;}
|
6
|
+
.ff-form .ff-title .ff-title-actions,.ff-table .ff-title .ff-title-actions{position:absolute;right:0;top:4px;padding:0 8px;}
|
7
|
+
.ff-form .ff-collapse,.ff-table .ff-collapse{background:url(/assets/glyphicons-halflings.png) -313px -119px;}
|
8
|
+
.ff-form .ff-collapsed.ff-collapse,.ff-table .ff-collapsed.ff-collapse{background:url(/assets/glyphicons-halflings.png) -456px -72px;}
|
9
|
+
.ff-form .ff-field-hint,.ff-table .ff-field-hint{background:url(/assets/glyphicons-halflings.png) -456px -72px;}
|
10
|
+
.ff-form .ff-tabs,.ff-table .ff-tabs{padding:4px 0;}.ff-form .ff-tabs ul.ff-tabs-header,.ff-table .ff-tabs ul.ff-tabs-header{list-style-type:none;margin:0;position:relative;border-bottom:1px solid #b1b1b1;}.ff-form .ff-tabs ul.ff-tabs-header li,.ff-table .ff-tabs ul.ff-tabs-header li{user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:pointer;display:inline-block;padding:4px 8px;margin-left:8px;margin-bottom:-1px;border:1px solid transparent;}.ff-form .ff-tabs ul.ff-tabs-header li img,.ff-table .ff-tabs ul.ff-tabs-header li img{margin:0 4px;height:16px;width:16px;}
|
11
|
+
.ff-form .ff-tabs ul.ff-tabs-header li.ff-selected,.ff-table .ff-tabs ul.ff-tabs-header li.ff-selected{background:#ffffcc;border:1px solid #b1b1b1;border-bottom:1px solid #ffffcc;}
|
12
|
+
.ff-form .ff-tabs .ff-tab-actions,.ff-table .ff-tabs .ff-tab-actions{padding:4px 8px;background:#ffffcc;border:1px solid #b1b1b1;margin-top:-1px;}
|
13
|
+
.ff-form .ff-tabs .ff-cols,.ff-table .ff-tabs .ff-cols{margin:4px 0 0 0;position:relative;font-size:13px;}.ff-form .ff-tabs .ff-cols .ff-col-100,.ff-table .ff-tabs .ff-cols .ff-col-100{width:100%;}
|
14
|
+
.ff-form .ff-tabs .ff-cols .ff-col-50,.ff-table .ff-tabs .ff-cols .ff-col-50{width:50%;float:left;}
|
15
|
+
.ff-form .ff-tabs .ff-cols .ff-col:first-child .ff-col-inner,.ff-table .ff-tabs .ff-cols .ff-col:first-child .ff-col-inner{padding-right:4px;}
|
16
|
+
.ff-form .ff-tabs .ff-cols .ff-col:last-child .ff-col-inner,.ff-table .ff-tabs .ff-cols .ff-col:last-child .ff-col-inner{padding-left:4px;}
|
17
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner,.ff-table .ff-tabs .ff-cols .ff-col-inner{padding:0;position:relative;}.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field{position:relative;border-bottom:1px solid #b1b1b1;}.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field:first-child,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field:first-child{border-top:1px solid #b1b1b1;}
|
18
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-label,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-label{display:table-cell;vertical-align:top;position:relative;width:150px;padding:4px 4px 4px 8px;background-color:#c8ffb0;border-right:3px solid transparent;}.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-label.ff-required,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-label.ff-required{border-right:3px solid #cf0000;}
|
19
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-label .ff-field-hint,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-label .ff-field-hint{display:block;height:16px;width:16px;position:absolute;right:0;top:8px;background-position:-96px -96px;}
|
20
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-value,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-value{display:table-cell;padding:4px;vertical-align:top;}.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-value .ff-field-actions,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-value .ff-field-actions{display:inline-block;border-left:1px solid #b1b1b1;padding-left:8px;margin-left:8px;}
|
21
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-field-before,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-field-before{padding-right:8px;}
|
22
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-field-after,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-field-after{padding-left:8px;}
|
23
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-complex-field .ff-complex-part,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-complex-field .ff-complex-part{display:inline-block;padding-right:8px;}
|
24
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-complex-field .ff-field,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-complex-field .ff-field{display:inline-block;border:none;padding-right:8px;}
|
25
|
+
.ff-form .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-select-field .ff-select-link,.ff-table .ff-tabs .ff-cols .ff-col-inner .ff-field .ff-select-field .ff-select-link{margin-left:8px;}
|
26
|
+
.ff-form .ff-tabs .ff-cols:after,.ff-table .ff-tabs .ff-cols:after{content:".";display:block;clear:both;width:0;height:0;overflow:hidden;}
|
27
|
+
.ff-form .ff-tabs input,.ff-table .ff-tabs input{padding:4px;margin:0;font-size:13px;}
|
28
|
+
.ff-form .ff-tabs select,.ff-table .ff-tabs select{padding:4px;margin:0;font-size:13px;width:auto;}
|
29
|
+
.ff-form .ff-tabs .ff-error input,.ff-table .ff-tabs .ff-error input{border:1px solid red;color:red;background:#fff8f8;}
|
30
|
+
.ff-form .ff-form-errors,.ff-table .ff-form-errors{margin:8px;padding:8px;border:1px solid red;background:#fee;color:red;}
|
31
|
+
.ff-form ul.ff-form-errors li,.ff-table ul.ff-form-errors li{margin-left:16px;}
|
32
|
+
.ff-form .ff-field-errors,.ff-table .ff-field-errors{color:red;padding:4px 0;}
|
33
|
+
.ff-form .ff-bottom-actions,.ff-table .ff-bottom-actions{padding:8px;border-top:1px solid #b1b1b1;background:#e0e0e0;}
|
34
|
+
.ff-form table.ff-common-table,.ff-table table.ff-common-table{margin-top:8px;width:100%;border-collapse:collapse;}.ff-form table.ff-common-table thead,.ff-table table.ff-common-table thead{text-align:left;border-top:1px solid #3316ff;border-bottom:1px solid #3316ff;background:#c8ffb0;}.ff-form table.ff-common-table thead th,.ff-table table.ff-common-table thead th{font-weight:normal;padding:4px 8px;}
|
35
|
+
.ff-form table.ff-common-table thead .ff-field-hint,.ff-table table.ff-common-table thead .ff-field-hint{display:inline-block;height:16px;width:16px;background-position:-96px -96px;}
|
36
|
+
.ff-form table.ff-common-table tbody td,.ff-table table.ff-common-table tbody td{padding:4px 8px;border-bottom:1px solid #3316ff;}
|
37
|
+
.ff-empty{color:#a0a0a0;}
|
38
|
+
.ff-table-empty{padding:32px;text-align:center;background-color:#f6f6f6;border:1px solid #a0a0a0;border-top:none;}
|
39
|
+
.ff-map{width:100%;height:100%;overflow:hidden;position:absolute;top:0;left:0;right:0;bottom:0;}.ff-map img{max-width:none;}
|
40
|
+
.ff-form .ff-title,.ff-table .ff-title{background-color:#cfc8ff;border-bottom:2px solid #3316ff;border-top:2px solid #3316ff;}
|
41
|
+
.tooltip-inner{white-space:pre;max-width:none;}
|