para 0.6.9 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/images/para/admin/tangram-mosaic.png +0 -0
- data/app/assets/images/para/admin/template-section.svg +23 -0
- data/app/assets/javascripts/para/admin.coffee +20 -0
- data/app/assets/javascripts/para/admin/tabs.coffee +22 -5
- data/app/assets/javascripts/para/admin/theme_actions.coffee +3 -3
- data/app/assets/javascripts/para/inputs/material-input.coffee +4 -0
- data/app/assets/javascripts/para/inputs/multi-select-input.coffee +173 -0
- data/app/assets/javascripts/para/inputs/nested_many.coffee +9 -9
- data/app/assets/stylesheets/para/admin.sass +5 -5
- data/app/assets/stylesheets/para/admin/main.sass +32 -0
- data/app/assets/stylesheets/para/admin/src/_alert.sass +17 -0
- data/app/assets/stylesheets/para/admin/src/_base.sass +51 -0
- data/app/assets/stylesheets/para/admin/src/_bootstrap-variables.scss +874 -0
- data/app/assets/stylesheets/para/admin/src/_breadcrumb.sass +22 -0
- data/app/assets/stylesheets/para/admin/src/_buttons.sass +107 -0
- data/app/assets/stylesheets/para/admin/src/_checkable.sass +94 -0
- data/app/assets/stylesheets/para/admin/src/_common.sass +203 -0
- data/app/assets/stylesheets/para/admin/src/_dropdown.sass +40 -0
- data/app/assets/stylesheets/para/admin/src/_form.sass +271 -0
- data/app/assets/stylesheets/para/admin/src/_list.sass +61 -0
- data/app/assets/stylesheets/para/admin/src/_mixins.sass +113 -0
- data/app/assets/stylesheets/para/admin/src/_multi-select.sass +91 -0
- data/app/assets/stylesheets/para/admin/src/_navigation.sass +150 -0
- data/app/assets/stylesheets/para/admin/src/_navtabs.sass +41 -0
- data/app/assets/stylesheets/para/admin/src/_nested-many.sass +69 -0
- data/app/assets/stylesheets/para/admin/src/_nested_one.sass +13 -0
- data/app/assets/stylesheets/para/admin/src/_orderable.sass +44 -0
- data/app/assets/stylesheets/para/admin/src/_page-loading.sass +39 -0
- data/app/assets/stylesheets/para/admin/src/_pagination.sass +34 -0
- data/app/assets/stylesheets/para/admin/src/_panel.sass +55 -0
- data/app/assets/stylesheets/para/admin/src/_responsive.sass +100 -0
- data/app/assets/stylesheets/para/admin/{theme → src}/_sorting.sass +11 -3
- data/app/assets/stylesheets/para/admin/src/_statcard.sass +41 -0
- data/app/assets/stylesheets/para/admin/src/_table.sass +33 -0
- data/app/assets/stylesheets/para/admin/src/_tree.sass +52 -0
- data/app/assets/stylesheets/para/admin/src/_variables.sass +37 -0
- data/app/assets/stylesheets/para/admin/src/_well.sass +12 -0
- data/app/assets/stylesheets/para/{admin/src → lib}/datetimepicker.sass +1 -3
- data/app/assets/stylesheets/para/{admin/src → lib}/fuelux.sass +3 -5
- data/app/assets/stylesheets/para/lib/jasny-bootstrap.sass +97 -0
- data/app/assets/stylesheets/para/{admin/src → lib}/redactor.sass +2 -5
- data/app/assets/stylesheets/para/lib/selectize.sass +112 -0
- data/app/assets/stylesheets/para/lib/slider.sass +12 -0
- data/app/controllers/concerns/para/admin/resource_controller_concerns.rb +14 -2
- data/app/controllers/para/admin/base_controller.rb +7 -0
- data/app/controllers/para/admin/crud_resources_controller.rb +13 -6
- data/app/controllers/para/admin/form_resources_controller.rb +5 -3
- data/app/controllers/para/admin/resources_controller.rb +9 -3
- data/app/controllers/para/admin/search_controller.rb +15 -0
- data/app/controllers/para/application_controller.rb +10 -2
- data/app/helpers/para/admin/page_helper.rb +9 -9
- data/app/helpers/para/application_helper.rb +1 -10
- data/app/helpers/para/form_helper.rb +5 -6
- data/app/helpers/para/model_helper.rb +13 -3
- data/app/helpers/para/ordering_helper.rb +1 -1
- data/app/helpers/para/search_results_helper.rb +16 -0
- data/app/helpers/para/tree_helper.rb +10 -6
- data/app/models/para/page.rb +5 -0
- data/app/models/para/page/section.rb +42 -0
- data/app/models/para/page/section_resource.rb +12 -0
- data/app/views/layouts/para/admin.html.haml +5 -8
- data/app/views/para/admin/dashboard.html.haml +21 -8
- data/app/views/para/admin/form_resources/show.html.haml +1 -1
- data/app/views/para/admin/imports/new.html.haml +2 -2
- data/app/views/para/admin/resources/_actions.html.haml +3 -3
- data/app/views/para/admin/resources/_add_button.html.haml +1 -1
- data/app/views/para/admin/resources/_exports_menu.html.haml +6 -6
- data/app/views/para/admin/resources/_filters.html.haml +7 -8
- data/app/views/para/admin/resources/_imports_menu.html.haml +6 -6
- data/app/views/para/admin/resources/_list.html.haml +14 -15
- data/app/views/para/admin/resources/_per_page_select.html.haml +4 -3
- data/app/views/para/admin/resources/_subclassable_add_button.html.haml +3 -3
- data/app/views/para/admin/resources/_tree.html.haml +7 -9
- data/app/views/para/admin/resources/_tree_item.html.haml +5 -6
- data/app/views/para/admin/resources/edit.html.haml +1 -1
- data/app/views/para/admin/resources/new.html.haml +1 -1
- data/app/views/para/admin/search/_result.html.haml +7 -0
- data/app/views/para/admin/search/index.html.haml +1 -0
- data/app/views/para/admin/settings_component/show.html.haml +1 -1
- data/app/views/para/admin/shared/_breadcrumbs.html.haml +2 -3
- data/app/views/para/admin/shared/_header.html.haml +16 -27
- data/app/views/para/admin/shared/_navigation.html.haml +20 -19
- data/app/views/para/form/_tabs.html.haml +6 -7
- data/app/views/para/inputs/_multi_select.html.haml +40 -0
- data/app/views/para/inputs/_nested_many.html.haml +4 -4
- data/app/views/para/inputs/multi_select/_no_items.html.haml +6 -0
- data/app/views/para/inputs/nested_many/_add.html.haml +1 -2
- data/app/views/para/inputs/nested_many/_add_with_subclasses.html.haml +4 -5
- data/app/views/para/inputs/nested_many/_container.html.haml +7 -8
- data/app/views/shared/_breadcrumbs.html.haml +4 -0
- data/config/locales/fr.yml +29 -4
- data/db/migrate/20170324125547_create_para_page_section_resources.rb +15 -0
- data/lib/generators/para/filters/templates/_filters.html.haml +3 -5
- data/lib/generators/para/install/templates/initializer.rb +12 -0
- data/lib/generators/para/page/section/section_generator.rb +13 -2
- data/lib/generators/para/page/section/templates/section.html.haml.erb +3 -0
- data/lib/generators/para/resource/resource_generator.rb +1 -1
- data/lib/para.rb +25 -21
- data/lib/para/attribute_field.rb +2 -0
- data/lib/para/attribute_field/base.rb +1 -1
- data/lib/para/attribute_field/belongs_to.rb +1 -1
- data/lib/para/attribute_field/boolean.rb +1 -1
- data/lib/para/attribute_field/friendly_id.rb +19 -0
- data/lib/para/attribute_field/has_many.rb +43 -4
- data/lib/para/attribute_field/nested_field.rb +46 -0
- data/lib/para/attribute_field/nested_many.rb +30 -9
- data/lib/para/attribute_field/nested_one.rb +28 -9
- data/lib/para/attribute_field/password.rb +1 -1
- data/lib/para/attribute_field/relation.rb +19 -1
- data/lib/para/attribute_field_mappings.rb +9 -3
- data/lib/para/breadcrumbs/breadcrumb.rb +57 -10
- data/lib/para/breadcrumbs/controller.rb +19 -6
- data/lib/para/breadcrumbs/manager.rb +9 -1
- data/lib/para/config.rb +3 -0
- data/lib/para/controller_resource.rb +34 -0
- data/lib/para/engine.rb +33 -14
- data/lib/para/exporter/base.rb +1 -1
- data/lib/para/ext.rb +1 -1
- data/lib/para/ext/active_record_nested_attributes.rb +51 -0
- data/lib/para/ext/paperclip.rb +2 -6
- data/lib/para/form_builder.rb +3 -0
- data/lib/para/form_builder/attributes_mappings_tracker.rb +45 -0
- data/lib/para/form_builder/containers.rb +13 -17
- data/lib/para/form_builder/nested_form.rb +2 -3
- data/lib/para/helpers.rb +8 -0
- data/lib/para/helpers/attributes_mappings.rb +13 -0
- data/lib/para/helpers/resource_name.rb +14 -0
- data/lib/para/inputs.rb +1 -0
- data/lib/para/inputs/multi_select_input.rb +90 -0
- data/lib/para/inputs/nested_many_input.rb +6 -1
- data/lib/para/markup/resources_table.rb +15 -11
- data/lib/para/model_field_parsers.rb +3 -2
- data/lib/para/model_field_parsers/base.rb +7 -2
- data/lib/para/model_field_parsers/friendly_id.rb +19 -0
- data/lib/para/model_field_parsers/relations.rb +20 -1
- data/lib/para/page/model.rb +3 -1
- data/lib/para/routes.rb +1 -0
- data/lib/para/simple_form_config.rb +85 -0
- data/lib/para/version.rb +1 -1
- data/lib/rails/routing_mapper.rb +5 -8
- data/vendor/assets/javascripts/jasny-bootstrap.js +577 -0
- data/vendor/assets/stylesheets/animate.css +3340 -0
- data/vendor/assets/stylesheets/hint.css +649 -0
- data/vendor/assets/stylesheets/jasny-bootstrap.css +287 -0
- metadata +114 -67
- data/app/assets/images/para/admin/bg.png +0 -0
- data/app/assets/javascripts/para/admin.js +0 -20
- data/app/assets/stylesheets/admin/theme.sass +0 -0
- data/app/assets/stylesheets/para/admin/src/jasny.bootstrap.sass +0 -40
- data/app/assets/stylesheets/para/admin/src/nested_many.sass +0 -5
- data/app/assets/stylesheets/para/admin/src/page-loading.sass +0 -24
- data/app/assets/stylesheets/para/admin/src/page-top-bar.sass +0 -9
- data/app/assets/stylesheets/para/admin/src/selectize.sass +0 -46
- data/app/assets/stylesheets/para/admin/src/slider.sass +0 -12
- data/app/assets/stylesheets/para/admin/theme.sass +0 -22
- data/app/assets/stylesheets/para/admin/theme/_base.sass +0 -176
- data/app/assets/stylesheets/para/admin/theme/_breadcrumb.sass +0 -75
- data/app/assets/stylesheets/para/admin/theme/_buttons.sass +0 -27
- data/app/assets/stylesheets/para/admin/theme/_checkable.sass +0 -108
- data/app/assets/stylesheets/para/admin/theme/_commonds.sass +0 -210
- data/app/assets/stylesheets/para/admin/theme/_dropdown.sass +0 -52
- data/app/assets/stylesheets/para/admin/theme/_form.sass +0 -150
- data/app/assets/stylesheets/para/admin/theme/_list.sass +0 -139
- data/app/assets/stylesheets/para/admin/theme/_navigation.sass +0 -229
- data/app/assets/stylesheets/para/admin/theme/_navtabs.sass +0 -151
- data/app/assets/stylesheets/para/admin/theme/_orderable.sass +0 -45
- data/app/assets/stylesheets/para/admin/theme/_panel.sass +0 -264
- data/app/assets/stylesheets/para/admin/theme/_responsive.sass +0 -123
- data/app/assets/stylesheets/para/admin/theme/_table.sass +0 -28
- data/app/assets/stylesheets/para/admin/theme/_tree.sass +0 -74
- data/app/assets/stylesheets/para/admin/theme/_variables.sass +0 -31
- data/app/assets/stylesheets/para/application.css +0 -15
- data/app/assets/stylesheets/para/lib/_variables.scss +0 -646
- data/app/assets/stylesheets/para/overrides/responsive.sass +0 -62
- data/app/assets/stylesheets/para/overrides/theme.sass +0 -172
- data/lib/para/ext/cancan.rb +0 -26
- data/vendor/assets/javascripts/jasny.bootstrap.min.js +0 -7
- data/vendor/assets/stylesheets/animate.min.css +0 -6
- data/vendor/assets/stylesheets/jasny.bootstrap.min.css +0 -7
|
@@ -27,7 +27,8 @@ module Para
|
|
|
27
27
|
resources: resources,
|
|
28
28
|
nested_locals: locals,
|
|
29
29
|
subclass: subclass,
|
|
30
|
-
subclasses: subclasses
|
|
30
|
+
subclasses: subclasses,
|
|
31
|
+
inset: inset?
|
|
31
32
|
}
|
|
32
33
|
)
|
|
33
34
|
end
|
|
@@ -59,6 +60,10 @@ module Para
|
|
|
59
60
|
(model.try(:descendants) || []).sort_by { |m| m.model_name.human }
|
|
60
61
|
)
|
|
61
62
|
end
|
|
63
|
+
|
|
64
|
+
def inset?
|
|
65
|
+
options.fetch(:inset, false)
|
|
66
|
+
end
|
|
62
67
|
end
|
|
63
68
|
end
|
|
64
69
|
end
|
|
@@ -44,7 +44,7 @@ module Para
|
|
|
44
44
|
# Append cells
|
|
45
45
|
cells << capture { block.call }
|
|
46
46
|
# Append actions empty cell
|
|
47
|
-
cells << content_tag(:th, '', class: 'actions'
|
|
47
|
+
cells << content_tag(:th, '', class: 'table-row-actions') if actions
|
|
48
48
|
|
|
49
49
|
# Output full header
|
|
50
50
|
content_tag(:thead) do
|
|
@@ -131,12 +131,10 @@ module Para
|
|
|
131
131
|
end
|
|
132
132
|
|
|
133
133
|
def actions_cell(resource)
|
|
134
|
-
content_tag(:td) do
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
end.compact.join.html_safe
|
|
139
|
-
end
|
|
134
|
+
content_tag(:td, class: 'table-row-actions') do
|
|
135
|
+
actions.map do |type|
|
|
136
|
+
send(:"#{ type }_button", resource)
|
|
137
|
+
end.compact.join.html_safe
|
|
140
138
|
end
|
|
141
139
|
end
|
|
142
140
|
|
|
@@ -149,7 +147,10 @@ module Para
|
|
|
149
147
|
|
|
150
148
|
options = {
|
|
151
149
|
method: :post,
|
|
152
|
-
class: 'btn btn-info'
|
|
150
|
+
class: 'btn btn-sm btn-icon-info btn-shadow hint--left',
|
|
151
|
+
aria: {
|
|
152
|
+
label: ::I18n.t('para.shared.copy')
|
|
153
|
+
}
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
view.link_to(path, options) do
|
|
@@ -162,7 +163,7 @@ module Para
|
|
|
162
163
|
resource, action: :edit, return_to: view.request.fullpath
|
|
163
164
|
)
|
|
164
165
|
|
|
165
|
-
view.link_to(path, class: 'btn btn-primary') do
|
|
166
|
+
view.link_to(path, class: 'btn btn-sm btn-icon-primary btn-shadow hint--left', aria: { label: ::I18n.t('para.shared.edit') }) do
|
|
166
167
|
content_tag(:i, '', class: 'fa fa-pencil')
|
|
167
168
|
end
|
|
168
169
|
end
|
|
@@ -175,11 +176,14 @@ module Para
|
|
|
175
176
|
data: {
|
|
176
177
|
confirm: ::I18n.t('para.list.delete_confirmation')
|
|
177
178
|
},
|
|
178
|
-
class: 'btn btn-danger'
|
|
179
|
+
class: 'btn btn-sm btn-icon-danger btn-shadow hint--left',
|
|
180
|
+
aria: {
|
|
181
|
+
label: ::I18n.t('para.shared.destroy')
|
|
182
|
+
}
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
view.link_to(path, options) do
|
|
182
|
-
content_tag(:i, '', class: 'fa fa-
|
|
186
|
+
content_tag(:i, '', class: 'fa fa-times')
|
|
183
187
|
end
|
|
184
188
|
end
|
|
185
189
|
|
|
@@ -4,9 +4,9 @@ module Para
|
|
|
4
4
|
@registered_parsers ||= {}
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def self.parse!(model, fields_hash)
|
|
7
|
+
def self.parse!(model, fields_hash, mappings)
|
|
8
8
|
registered_parsers.each do |_, parser_class|
|
|
9
|
-
parser = parser_class.new(model, fields_hash)
|
|
9
|
+
parser = parser_class.new(model, fields_hash, mappings)
|
|
10
10
|
parser.parse! if parser.applicable?
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -20,6 +20,7 @@ require 'para/model_field_parsers/orderable'
|
|
|
20
20
|
require 'para/model_field_parsers/relations'
|
|
21
21
|
require 'para/model_field_parsers/redactor'
|
|
22
22
|
require 'para/model_field_parsers/globalize'
|
|
23
|
+
require 'para/model_field_parsers/friendly_id'
|
|
23
24
|
require 'para/model_field_parsers/store'
|
|
24
25
|
require 'para/model_field_parsers/enums'
|
|
25
26
|
require 'para/model_field_parsers/closure_tree'
|
|
@@ -5,16 +5,21 @@ module Para
|
|
|
5
5
|
ModelFieldParsers.registered_parsers[key] = parser
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
attr_reader :model, :fields_hash
|
|
8
|
+
attr_reader :model, :fields_hash, :mappings
|
|
9
9
|
|
|
10
|
-
def initialize(model, fields_hash)
|
|
10
|
+
def initialize(model, fields_hash, mappings)
|
|
11
11
|
@model = model
|
|
12
12
|
@fields_hash = fields_hash
|
|
13
|
+
@mappings = mappings
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def applicable?
|
|
16
17
|
true
|
|
17
18
|
end
|
|
19
|
+
|
|
20
|
+
def find_attributes_for_mapping(type)
|
|
21
|
+
mappings.select { |k, v| v == type.to_s }.keys.map(&:to_sym)
|
|
22
|
+
end
|
|
18
23
|
end
|
|
19
24
|
end
|
|
20
25
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module ModelFieldParsers
|
|
3
|
+
class FriendlyId < Para::ModelFieldParsers::Base
|
|
4
|
+
register :friendly_id, self
|
|
5
|
+
|
|
6
|
+
def parse!
|
|
7
|
+
key = model.friendly_id_config.slug_column
|
|
8
|
+
|
|
9
|
+
fields_hash[key] = AttributeField::FriendlyId.new(
|
|
10
|
+
model, name: key, type: 'friendly_id'
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def applicable?
|
|
15
|
+
!!model.try(:friendly_id_config)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -4,6 +4,20 @@ module Para
|
|
|
4
4
|
register :relations, self
|
|
5
5
|
|
|
6
6
|
def parse!
|
|
7
|
+
# Catch multi select inputs from form attributes mappings
|
|
8
|
+
find_attributes_for_mapping(:multi_select).each do |attribute|
|
|
9
|
+
fields_hash[attribute] = AttributeField::HasManyField.new(
|
|
10
|
+
model, name: attribute, type: 'has_many', field_type: 'multi_select'
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Catch multi select inputs from form attributes mappings
|
|
15
|
+
find_attributes_for_mapping(:nested_many).each do |attribute|
|
|
16
|
+
fields_hash[attribute] = AttributeField::NestedManyField.new(
|
|
17
|
+
model, name: attribute, type: 'has_many', field_type: 'nested_many'
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
7
21
|
model.reflections.each do |name, reflection|
|
|
8
22
|
# We ensure that name is a symbol and not a string for 4.2+
|
|
9
23
|
# versions of AR
|
|
@@ -11,11 +25,16 @@ module Para
|
|
|
11
25
|
# `fields_hash` is already a `HashWithIndifferentAccess`
|
|
12
26
|
name = name.to_sym
|
|
13
27
|
|
|
28
|
+
# Do not process component relations
|
|
14
29
|
next if name == :component
|
|
30
|
+
# Do not reprocess attributes that were already catched with
|
|
31
|
+
# attributes mappings above
|
|
32
|
+
next if AttributeField::RelationField == fields_hash[name]
|
|
15
33
|
|
|
16
34
|
# Remove foreign key, if existing, from fields
|
|
17
35
|
fields_hash.delete(reflection.foreign_key.to_s)
|
|
18
36
|
|
|
37
|
+
# Do not process polymorphic belongs to for now ...
|
|
19
38
|
if reflection.options[:polymorphic] == true
|
|
20
39
|
fields_hash.delete(reflection.foreign_type.to_s)
|
|
21
40
|
next
|
|
@@ -36,7 +55,7 @@ module Para
|
|
|
36
55
|
remove_counter_cache_column!(name, reflection)
|
|
37
56
|
|
|
38
57
|
fields_hash[name] = AttributeField::HasManyField.new(
|
|
39
|
-
model, name: name, type: 'has_many', field_type: '
|
|
58
|
+
model, name: name, type: 'has_many', field_type: 'multi_select'
|
|
40
59
|
)
|
|
41
60
|
elsif !reflection.options[:through]
|
|
42
61
|
fields_hash[name] = AttributeField::BelongsToField.new(
|
data/lib/para/page/model.rb
CHANGED
|
@@ -4,7 +4,9 @@ module Para
|
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
6
|
included do
|
|
7
|
-
has_many :sections, -> { ordered }, class_name: '::Para::Page::Section',
|
|
7
|
+
has_many :sections, -> { ordered }, class_name: '::Para::Page::Section',
|
|
8
|
+
as: :page,
|
|
9
|
+
dependent: :destroy
|
|
8
10
|
accepts_nested_attributes_for :sections, allow_destroy: true
|
|
9
11
|
end
|
|
10
12
|
end
|
data/lib/para/routes.rb
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Default simple form bootstrap initializer mechanism
|
|
2
|
+
module Para
|
|
3
|
+
module SimpleFormConfig
|
|
4
|
+
def self.wrapper_mappings
|
|
5
|
+
{
|
|
6
|
+
check_boxes: :para_vertical_radio_and_checkboxes,
|
|
7
|
+
radio_buttons: :para_vertical_radio_and_checkboxes,
|
|
8
|
+
boolean: :para_vertical_radio_and_checkboxes,
|
|
9
|
+
datetime: :para_multi_select,
|
|
10
|
+
date: :para_multi_select,
|
|
11
|
+
time: :para_multi_select,
|
|
12
|
+
file: :para_vertical_file_input
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.configure
|
|
17
|
+
# Use this setup block to configure all options available in SimpleForm.
|
|
18
|
+
SimpleForm.setup do |config|
|
|
19
|
+
config.error_notification_class = 'alert alert-danger'
|
|
20
|
+
config.button_class = 'btn'
|
|
21
|
+
config.boolean_label_class = nil
|
|
22
|
+
|
|
23
|
+
config.wrappers :para_vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
|
|
24
|
+
b.use :html5
|
|
25
|
+
b.use :placeholder
|
|
26
|
+
b.optional :maxlength
|
|
27
|
+
b.optional :minlength
|
|
28
|
+
b.optional :pattern
|
|
29
|
+
b.optional :min_max
|
|
30
|
+
b.optional :readonly
|
|
31
|
+
b.use :label, class: 'control-label'
|
|
32
|
+
|
|
33
|
+
b.use :input, class: 'form-control'
|
|
34
|
+
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
|
|
35
|
+
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
config.wrappers :para_vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
|
|
39
|
+
b.use :html5
|
|
40
|
+
b.use :placeholder
|
|
41
|
+
b.optional :maxlength
|
|
42
|
+
b.optional :minlength
|
|
43
|
+
b.optional :readonly
|
|
44
|
+
b.use :label, class: 'control-label'
|
|
45
|
+
|
|
46
|
+
b.use :input
|
|
47
|
+
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
|
|
48
|
+
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
config.wrappers :para_vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
|
|
52
|
+
b.use :html5
|
|
53
|
+
b.optional :readonly
|
|
54
|
+
|
|
55
|
+
b.wrapper tag: 'div', class: 'checkbox' do |ba|
|
|
56
|
+
ba.use :label_input
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
|
|
60
|
+
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
config.wrappers :para_vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
|
|
64
|
+
b.use :html5
|
|
65
|
+
b.optional :readonly
|
|
66
|
+
b.use :label, class: 'control-label'
|
|
67
|
+
b.use :input
|
|
68
|
+
b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
|
|
69
|
+
b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
config.wrappers :para_multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
|
|
73
|
+
b.use :html5
|
|
74
|
+
b.optional :readonly
|
|
75
|
+
b.use :label, class: 'control-label'
|
|
76
|
+
b.wrapper tag: 'div', class: 'form-inline' do |ba|
|
|
77
|
+
ba.use :input, class: 'form-control'
|
|
78
|
+
ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
|
|
79
|
+
ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/para/version.rb
CHANGED
data/lib/rails/routing_mapper.rb
CHANGED
|
@@ -15,16 +15,14 @@ module ActionDispatch
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def component(component_name, options = {}, &block)
|
|
18
|
-
as,
|
|
18
|
+
as, component, endpoint = component_informations_from(
|
|
19
19
|
component_name, options
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
controller = options.fetch(:controller, "#{ component_name }_component")
|
|
24
23
|
imports_controller = options.fetch(:imports_controller, '/para/admin/imports')
|
|
25
24
|
exports_controller = options.fetch(:exports_controller, '/para/admin/exports')
|
|
26
25
|
|
|
27
|
-
|
|
28
26
|
constraints Para::Routing::ComponentNameConstraint.new(component) do
|
|
29
27
|
namespace :admin do
|
|
30
28
|
defaults(component: component) do
|
|
@@ -54,7 +52,7 @@ module ActionDispatch
|
|
|
54
52
|
options[:scope] ||= ':model'
|
|
55
53
|
end
|
|
56
54
|
|
|
57
|
-
as,
|
|
55
|
+
as, component, endpoint = component_informations_from(
|
|
58
56
|
component_name, options
|
|
59
57
|
)
|
|
60
58
|
|
|
@@ -105,7 +103,7 @@ module ActionDispatch
|
|
|
105
103
|
options[:scope] ||= ':model'
|
|
106
104
|
end
|
|
107
105
|
|
|
108
|
-
as,
|
|
106
|
+
as, component, endpoint = component_informations_from(
|
|
109
107
|
component_name, options
|
|
110
108
|
)
|
|
111
109
|
|
|
@@ -151,10 +149,9 @@ module ActionDispatch
|
|
|
151
149
|
def component_informations_from(component_name, options)
|
|
152
150
|
component = options.fetch(:component, component_name.to_s)
|
|
153
151
|
as = options.fetch(:as, component_name)
|
|
154
|
-
controller = options.fetch(:controller, "#{ component_name }_component")
|
|
155
152
|
endpoint = ":component/:component_id"
|
|
156
153
|
|
|
157
|
-
[as,
|
|
154
|
+
[as, component, endpoint]
|
|
158
155
|
end
|
|
159
156
|
|
|
160
157
|
def add_extensions_for(type)
|
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Jasny Bootstrap v3.1.3 (http://jasny.github.io/bootstrap)
|
|
3
|
+
* Copyright 2012-2014 Arnold Daniels
|
|
4
|
+
* Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
if (typeof jQuery === 'undefined') { throw new Error('Jasny Bootstrap\'s JavaScript requires jQuery') }
|
|
8
|
+
|
|
9
|
+
/* ========================================================================
|
|
10
|
+
* Bootstrap: transition.js v3.1.3
|
|
11
|
+
* http://getbootstrap.com/javascript/#transitions
|
|
12
|
+
* ========================================================================
|
|
13
|
+
* Copyright 2011-2014 Twitter, Inc.
|
|
14
|
+
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
15
|
+
* ======================================================================== */
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
+function ($) {
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
|
|
22
|
+
// ============================================================
|
|
23
|
+
|
|
24
|
+
function transitionEnd() {
|
|
25
|
+
var el = document.createElement('bootstrap')
|
|
26
|
+
|
|
27
|
+
var transEndEventNames = {
|
|
28
|
+
WebkitTransition : 'webkitTransitionEnd',
|
|
29
|
+
MozTransition : 'transitionend',
|
|
30
|
+
OTransition : 'oTransitionEnd otransitionend',
|
|
31
|
+
transition : 'transitionend'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (var name in transEndEventNames) {
|
|
35
|
+
if (el.style[name] !== undefined) {
|
|
36
|
+
return { end: transEndEventNames[name] }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false // explicit for ie8 ( ._.)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if ($.support.transition !== undefined) return // Prevent conflict with Twitter Bootstrap
|
|
44
|
+
|
|
45
|
+
// http://blog.alexmaccaw.com/css-transitions
|
|
46
|
+
$.fn.emulateTransitionEnd = function (duration) {
|
|
47
|
+
var called = false, $el = this
|
|
48
|
+
$(this).one($.support.transition.end, function () { called = true })
|
|
49
|
+
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
|
|
50
|
+
setTimeout(callback, duration)
|
|
51
|
+
return this
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
$(function () {
|
|
55
|
+
$.support.transition = transitionEnd()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
}(window.jQuery);
|
|
59
|
+
|
|
60
|
+
/* ========================================================================
|
|
61
|
+
* Bootstrap: offcanvas.js v3.1.3
|
|
62
|
+
* http://jasny.github.io/bootstrap/javascript/#offcanvas
|
|
63
|
+
* ========================================================================
|
|
64
|
+
* Copyright 2013-2014 Arnold Daniels
|
|
65
|
+
*
|
|
66
|
+
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
67
|
+
* you may not use this file except in compliance with the License.
|
|
68
|
+
* You may obtain a copy of the License at
|
|
69
|
+
*
|
|
70
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
71
|
+
*
|
|
72
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
73
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
74
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
75
|
+
* See the License for the specific language governing permissions and
|
|
76
|
+
* limitations under the License.
|
|
77
|
+
* ======================================================================== */
|
|
78
|
+
|
|
79
|
+
+function ($) { "use strict";
|
|
80
|
+
|
|
81
|
+
// OFFCANVAS PUBLIC CLASS DEFINITION
|
|
82
|
+
// =================================
|
|
83
|
+
|
|
84
|
+
var OffCanvas = function (element, options) {
|
|
85
|
+
this.$element = $(element)
|
|
86
|
+
this.options = $.extend({}, OffCanvas.DEFAULTS, options)
|
|
87
|
+
this.state = null
|
|
88
|
+
this.placement = null
|
|
89
|
+
|
|
90
|
+
if (this.options.recalc) {
|
|
91
|
+
this.calcClone()
|
|
92
|
+
$(window).on('resize', $.proxy(this.recalc, this))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (this.options.autohide)
|
|
96
|
+
$(document).on('click', $.proxy(this.autohide, this))
|
|
97
|
+
|
|
98
|
+
if (this.options.toggle) this.toggle()
|
|
99
|
+
|
|
100
|
+
if (this.options.disablescrolling) {
|
|
101
|
+
this.options.disableScrolling = this.options.disablescrolling
|
|
102
|
+
delete this.options.disablescrolling
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
OffCanvas.DEFAULTS = {
|
|
107
|
+
toggle: true,
|
|
108
|
+
placement: 'auto',
|
|
109
|
+
autohide: true,
|
|
110
|
+
recalc: true,
|
|
111
|
+
disableScrolling: true
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
OffCanvas.prototype.offset = function () {
|
|
115
|
+
switch (this.placement) {
|
|
116
|
+
case 'left':
|
|
117
|
+
case 'right': return this.$element.outerWidth()
|
|
118
|
+
case 'top':
|
|
119
|
+
case 'bottom': return this.$element.outerHeight()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
OffCanvas.prototype.calcPlacement = function () {
|
|
124
|
+
if (this.options.placement !== 'auto') {
|
|
125
|
+
this.placement = this.options.placement
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!this.$element.hasClass('in')) {
|
|
130
|
+
this.$element.css('visiblity', 'hidden !important').addClass('in')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
var horizontal = $(window).width() / this.$element.width()
|
|
134
|
+
var vertical = $(window).height() / this.$element.height()
|
|
135
|
+
|
|
136
|
+
var element = this.$element
|
|
137
|
+
function ab(a, b) {
|
|
138
|
+
if (element.css(b) === 'auto') return a
|
|
139
|
+
if (element.css(a) === 'auto') return b
|
|
140
|
+
|
|
141
|
+
var size_a = parseInt(element.css(a), 10)
|
|
142
|
+
var size_b = parseInt(element.css(b), 10)
|
|
143
|
+
|
|
144
|
+
return size_a > size_b ? b : a
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.placement = horizontal >= vertical ? ab('left', 'right') : ab('top', 'bottom')
|
|
148
|
+
|
|
149
|
+
if (this.$element.css('visibility') === 'hidden !important') {
|
|
150
|
+
this.$element.removeClass('in').css('visiblity', '')
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
OffCanvas.prototype.opposite = function (placement) {
|
|
155
|
+
switch (placement) {
|
|
156
|
+
case 'top': return 'bottom'
|
|
157
|
+
case 'left': return 'right'
|
|
158
|
+
case 'bottom': return 'top'
|
|
159
|
+
case 'right': return 'left'
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
OffCanvas.prototype.getCanvasElements = function() {
|
|
164
|
+
// Return a set containing the canvas plus all fixed elements
|
|
165
|
+
var canvas = this.options.canvas ? $(this.options.canvas) : this.$element
|
|
166
|
+
|
|
167
|
+
var fixed_elements = canvas.find('*').filter(function() {
|
|
168
|
+
return $(this).css('position') === 'fixed'
|
|
169
|
+
}).not(this.options.exclude)
|
|
170
|
+
|
|
171
|
+
return canvas.add(fixed_elements)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
OffCanvas.prototype.slide = function (elements, offset, callback) {
|
|
175
|
+
// Use jQuery animation if CSS transitions aren't supported
|
|
176
|
+
if (!$.support.transition) {
|
|
177
|
+
var anim = {}
|
|
178
|
+
anim[this.placement] = "+=" + offset
|
|
179
|
+
return elements.animate(anim, 350, callback)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
var placement = this.placement
|
|
183
|
+
var opposite = this.opposite(placement)
|
|
184
|
+
|
|
185
|
+
elements.each(function() {
|
|
186
|
+
if ($(this).css(placement) !== 'auto')
|
|
187
|
+
$(this).css(placement, (parseInt($(this).css(placement), 10) || 0) + offset)
|
|
188
|
+
|
|
189
|
+
if ($(this).css(opposite) !== 'auto')
|
|
190
|
+
$(this).css(opposite, (parseInt($(this).css(opposite), 10) || 0) - offset)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
this.$element
|
|
194
|
+
.one($.support.transition.end, callback)
|
|
195
|
+
.emulateTransitionEnd(350)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
OffCanvas.prototype.disableScrolling = function() {
|
|
199
|
+
var bodyWidth = $('body').width()
|
|
200
|
+
var prop = 'padding-' + this.opposite(this.placement)
|
|
201
|
+
|
|
202
|
+
if ($('body').data('offcanvas-style') === undefined) {
|
|
203
|
+
$('body').data('offcanvas-style', $('body').attr('style') || '')
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
$('body').css('overflow', 'hidden')
|
|
207
|
+
|
|
208
|
+
if ($('body').width() > bodyWidth) {
|
|
209
|
+
var padding = parseInt($('body').css(prop), 10) + $('body').width() - bodyWidth
|
|
210
|
+
|
|
211
|
+
setTimeout(function() {
|
|
212
|
+
$('body').css(prop, padding)
|
|
213
|
+
}, 1)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
OffCanvas.prototype.show = function () {
|
|
218
|
+
if (this.state) return
|
|
219
|
+
|
|
220
|
+
var startEvent = $.Event('show.bs.offcanvas')
|
|
221
|
+
this.$element.trigger(startEvent)
|
|
222
|
+
if (startEvent.isDefaultPrevented()) return
|
|
223
|
+
|
|
224
|
+
this.state = 'slide-in'
|
|
225
|
+
this.calcPlacement();
|
|
226
|
+
|
|
227
|
+
var elements = this.getCanvasElements()
|
|
228
|
+
var placement = this.placement
|
|
229
|
+
var opposite = this.opposite(placement)
|
|
230
|
+
var offset = this.offset()
|
|
231
|
+
|
|
232
|
+
if (elements.index(this.$element) !== -1) {
|
|
233
|
+
$(this.$element).data('offcanvas-style', $(this.$element).attr('style') || '')
|
|
234
|
+
this.$element.css(placement, -1 * offset)
|
|
235
|
+
this.$element.css(placement); // Workaround: Need to get the CSS property for it to be applied before the next line of code
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
elements.addClass('canvas-sliding').each(function() {
|
|
239
|
+
if ($(this).data('offcanvas-style') === undefined) $(this).data('offcanvas-style', $(this).attr('style') || '')
|
|
240
|
+
if ($(this).css('position') === 'static') $(this).css('position', 'relative')
|
|
241
|
+
if (($(this).css(placement) === 'auto' || $(this).css(placement) === '0px') &&
|
|
242
|
+
($(this).css(opposite) === 'auto' || $(this).css(opposite) === '0px')) {
|
|
243
|
+
$(this).css(placement, 0)
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
if (this.options.disableScrolling) this.disableScrolling()
|
|
248
|
+
|
|
249
|
+
var complete = function () {
|
|
250
|
+
if (this.state != 'slide-in') return
|
|
251
|
+
|
|
252
|
+
this.state = 'slid'
|
|
253
|
+
|
|
254
|
+
elements.removeClass('canvas-sliding').addClass('canvas-slid')
|
|
255
|
+
this.$element.trigger('shown.bs.offcanvas')
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
setTimeout($.proxy(function() {
|
|
259
|
+
this.$element.addClass('in')
|
|
260
|
+
this.slide(elements, offset, $.proxy(complete, this))
|
|
261
|
+
}, this), 1)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
OffCanvas.prototype.hide = function (fast) {
|
|
265
|
+
if (this.state !== 'slid') return
|
|
266
|
+
|
|
267
|
+
var startEvent = $.Event('hide.bs.offcanvas')
|
|
268
|
+
this.$element.trigger(startEvent)
|
|
269
|
+
if (startEvent.isDefaultPrevented()) return
|
|
270
|
+
|
|
271
|
+
this.state = 'slide-out'
|
|
272
|
+
|
|
273
|
+
var elements = $('.canvas-slid')
|
|
274
|
+
var placement = this.placement
|
|
275
|
+
var offset = -1 * this.offset()
|
|
276
|
+
|
|
277
|
+
var complete = function () {
|
|
278
|
+
if (this.state != 'slide-out') return
|
|
279
|
+
|
|
280
|
+
this.state = null
|
|
281
|
+
this.placement = null
|
|
282
|
+
|
|
283
|
+
this.$element.removeClass('in')
|
|
284
|
+
|
|
285
|
+
elements.removeClass('canvas-sliding')
|
|
286
|
+
elements.add(this.$element).add('body').each(function() {
|
|
287
|
+
$(this).attr('style', $(this).data('offcanvas-style')).removeData('offcanvas-style')
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
this.$element.trigger('hidden.bs.offcanvas')
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
elements.removeClass('canvas-slid').addClass('canvas-sliding')
|
|
294
|
+
|
|
295
|
+
setTimeout($.proxy(function() {
|
|
296
|
+
this.slide(elements, offset, $.proxy(complete, this))
|
|
297
|
+
}, this), 1)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
OffCanvas.prototype.toggle = function () {
|
|
301
|
+
if (this.state === 'slide-in' || this.state === 'slide-out') return
|
|
302
|
+
this[this.state === 'slid' ? 'hide' : 'show']()
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
OffCanvas.prototype.calcClone = function() {
|
|
306
|
+
this.$calcClone = this.$element.clone()
|
|
307
|
+
.html('')
|
|
308
|
+
.addClass('offcanvas-clone').removeClass('in')
|
|
309
|
+
.appendTo($('body'))
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
OffCanvas.prototype.recalc = function () {
|
|
313
|
+
if (this.$calcClone.css('display') === 'none' || (this.state !== 'slid' && this.state !== 'slide-in')) return
|
|
314
|
+
|
|
315
|
+
this.state = null
|
|
316
|
+
this.placement = null
|
|
317
|
+
var elements = this.getCanvasElements()
|
|
318
|
+
|
|
319
|
+
this.$element.removeClass('in')
|
|
320
|
+
|
|
321
|
+
elements.removeClass('canvas-slid')
|
|
322
|
+
elements.add(this.$element).add('body').each(function() {
|
|
323
|
+
$(this).attr('style', $(this).data('offcanvas-style')).removeData('offcanvas-style')
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
OffCanvas.prototype.autohide = function (e) {
|
|
328
|
+
if ($(e.target).closest(this.$element).length === 0) this.hide()
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// OFFCANVAS PLUGIN DEFINITION
|
|
332
|
+
// ==========================
|
|
333
|
+
|
|
334
|
+
var old = $.fn.offcanvas
|
|
335
|
+
|
|
336
|
+
$.fn.offcanvas = function (option) {
|
|
337
|
+
return this.each(function () {
|
|
338
|
+
var $this = $(this)
|
|
339
|
+
var data = $this.data('bs.offcanvas')
|
|
340
|
+
var options = $.extend({}, OffCanvas.DEFAULTS, $this.data(), typeof option === 'object' && option)
|
|
341
|
+
|
|
342
|
+
if (!data) $this.data('bs.offcanvas', (data = new OffCanvas(this, options)))
|
|
343
|
+
if (typeof option === 'string') data[option]()
|
|
344
|
+
})
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
$.fn.offcanvas.Constructor = OffCanvas
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
// OFFCANVAS NO CONFLICT
|
|
351
|
+
// ====================
|
|
352
|
+
|
|
353
|
+
$.fn.offcanvas.noConflict = function () {
|
|
354
|
+
$.fn.offcanvas = old
|
|
355
|
+
return this
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
// OFFCANVAS DATA-API
|
|
360
|
+
// =================
|
|
361
|
+
|
|
362
|
+
$(document).on('click.bs.offcanvas.data-api', '[data-toggle=offcanvas]', function (e) {
|
|
363
|
+
var $this = $(this), href
|
|
364
|
+
var target = $this.attr('data-target')
|
|
365
|
+
|| e.preventDefault()
|
|
366
|
+
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
|
|
367
|
+
var $canvas = $(target)
|
|
368
|
+
var data = $canvas.data('bs.offcanvas')
|
|
369
|
+
var option = data ? 'toggle' : $this.data()
|
|
370
|
+
|
|
371
|
+
e.stopPropagation()
|
|
372
|
+
|
|
373
|
+
if (data) data.toggle()
|
|
374
|
+
else $canvas.offcanvas(option)
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
}(window.jQuery);
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
/* ===========================================================
|
|
381
|
+
* Bootstrap: fileinput.js v3.1.3
|
|
382
|
+
* http://jasny.github.com/bootstrap/javascript/#fileinput
|
|
383
|
+
* ===========================================================
|
|
384
|
+
* Copyright 2012-2014 Arnold Daniels
|
|
385
|
+
*
|
|
386
|
+
* Licensed under the Apache License, Version 2.0 (the "License")
|
|
387
|
+
* you may not use this file except in compliance with the License.
|
|
388
|
+
* You may obtain a copy of the License at
|
|
389
|
+
*
|
|
390
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
391
|
+
*
|
|
392
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
393
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
394
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
395
|
+
* See the License for the specific language governing permissions and
|
|
396
|
+
* limitations under the License.
|
|
397
|
+
* ========================================================== */
|
|
398
|
+
|
|
399
|
+
+function ($) { "use strict";
|
|
400
|
+
|
|
401
|
+
var isIE = window.navigator.appName == 'Microsoft Internet Explorer'
|
|
402
|
+
|
|
403
|
+
// FILEUPLOAD PUBLIC CLASS DEFINITION
|
|
404
|
+
// =================================
|
|
405
|
+
|
|
406
|
+
var Fileinput = function (element, options) {
|
|
407
|
+
this.$element = $(element)
|
|
408
|
+
|
|
409
|
+
this.$input = this.$element.find(':file')
|
|
410
|
+
if (this.$input.length === 0) return
|
|
411
|
+
|
|
412
|
+
this.name = this.$input.attr('name') || options.name
|
|
413
|
+
|
|
414
|
+
this.$hidden = this.$element.find('input[type=hidden][name="' + this.name + '"]')
|
|
415
|
+
if (this.$hidden.length === 0) {
|
|
416
|
+
this.$hidden = $('<input type="hidden">').insertBefore(this.$input)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
this.$preview = this.$element.find('.fileinput-preview')
|
|
420
|
+
var height = this.$preview.css('height')
|
|
421
|
+
if (this.$preview.css('display') !== 'inline' && height !== '0px' && height !== 'none') {
|
|
422
|
+
this.$preview.css('line-height', height)
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
this.original = {
|
|
426
|
+
exists: this.$element.hasClass('fileinput-exists'),
|
|
427
|
+
preview: this.$preview.html(),
|
|
428
|
+
hiddenVal: this.$hidden.val()
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
this.listen()
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
Fileinput.prototype.listen = function() {
|
|
435
|
+
this.$input.on('change.bs.fileinput', $.proxy(this.change, this))
|
|
436
|
+
$(this.$input[0].form).on('reset.bs.fileinput', $.proxy(this.reset, this))
|
|
437
|
+
|
|
438
|
+
this.$element.find('[data-trigger="fileinput"]').on('click.bs.fileinput', $.proxy(this.trigger, this))
|
|
439
|
+
this.$element.find('[data-dismiss="fileinput"]').on('click.bs.fileinput', $.proxy(this.clear, this))
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
Fileinput.prototype.change = function(e) {
|
|
443
|
+
var files = e.target.files === undefined ? (e.target && e.target.value ? [{ name: e.target.value.replace(/^.+\\/, '')}] : []) : e.target.files
|
|
444
|
+
|
|
445
|
+
e.stopPropagation()
|
|
446
|
+
|
|
447
|
+
if (files.length === 0) {
|
|
448
|
+
this.clear()
|
|
449
|
+
return
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
this.$hidden.val('')
|
|
453
|
+
this.$hidden.attr('name', '')
|
|
454
|
+
this.$input.attr('name', this.name)
|
|
455
|
+
|
|
456
|
+
var file = files[0]
|
|
457
|
+
|
|
458
|
+
if (this.$preview.length > 0 && (typeof file.type !== "undefined" ? file.type.match(/^image\/(gif|png|jpeg)$/) : file.name.match(/\.(gif|png|jpe?g)$/i)) && typeof FileReader !== "undefined") {
|
|
459
|
+
var reader = new FileReader()
|
|
460
|
+
var preview = this.$preview
|
|
461
|
+
var element = this.$element
|
|
462
|
+
|
|
463
|
+
reader.onload = function(re) {
|
|
464
|
+
var $img = $('<img>')
|
|
465
|
+
$img[0].src = re.target.result
|
|
466
|
+
files[0].result = re.target.result
|
|
467
|
+
|
|
468
|
+
element.find('.fileinput-filename').text(file.name)
|
|
469
|
+
|
|
470
|
+
// if parent has max-height, using `(max-)height: 100%` on child doesn't take padding and border into account
|
|
471
|
+
if (preview.css('max-height') != 'none') $img.css('max-height', parseInt(preview.css('max-height'), 10) - parseInt(preview.css('padding-top'), 10) - parseInt(preview.css('padding-bottom'), 10) - parseInt(preview.css('border-top'), 10) - parseInt(preview.css('border-bottom'), 10))
|
|
472
|
+
|
|
473
|
+
preview.html($img)
|
|
474
|
+
element.addClass('fileinput-exists').removeClass('fileinput-new')
|
|
475
|
+
|
|
476
|
+
element.trigger('change.bs.fileinput', files)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
reader.readAsDataURL(file)
|
|
480
|
+
} else {
|
|
481
|
+
this.$element.find('.fileinput-filename').text(file.name)
|
|
482
|
+
this.$preview.text(file.name)
|
|
483
|
+
|
|
484
|
+
this.$element.addClass('fileinput-exists').removeClass('fileinput-new')
|
|
485
|
+
|
|
486
|
+
this.$element.trigger('change.bs.fileinput')
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
Fileinput.prototype.clear = function(e) {
|
|
491
|
+
if (e) e.preventDefault()
|
|
492
|
+
|
|
493
|
+
this.$hidden.val('')
|
|
494
|
+
this.$hidden.attr('name', this.name)
|
|
495
|
+
this.$input.attr('name', '')
|
|
496
|
+
|
|
497
|
+
//ie8+ doesn't support changing the value of input with type=file so clone instead
|
|
498
|
+
if (isIE) {
|
|
499
|
+
var inputClone = this.$input.clone(true);
|
|
500
|
+
this.$input.after(inputClone);
|
|
501
|
+
this.$input.remove();
|
|
502
|
+
this.$input = inputClone;
|
|
503
|
+
} else {
|
|
504
|
+
this.$input.val('')
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
this.$preview.html('')
|
|
508
|
+
this.$element.find('.fileinput-filename').text('')
|
|
509
|
+
this.$element.addClass('fileinput-new').removeClass('fileinput-exists')
|
|
510
|
+
|
|
511
|
+
if (e !== undefined) {
|
|
512
|
+
this.$input.trigger('change')
|
|
513
|
+
this.$element.trigger('clear.bs.fileinput')
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
Fileinput.prototype.reset = function() {
|
|
518
|
+
this.clear()
|
|
519
|
+
|
|
520
|
+
this.$hidden.val(this.original.hiddenVal)
|
|
521
|
+
this.$preview.html(this.original.preview)
|
|
522
|
+
this.$element.find('.fileinput-filename').text('')
|
|
523
|
+
|
|
524
|
+
if (this.original.exists) this.$element.addClass('fileinput-exists').removeClass('fileinput-new')
|
|
525
|
+
else this.$element.addClass('fileinput-new').removeClass('fileinput-exists')
|
|
526
|
+
|
|
527
|
+
this.$element.trigger('reset.bs.fileinput')
|
|
528
|
+
},
|
|
529
|
+
|
|
530
|
+
Fileinput.prototype.trigger = function(e) {
|
|
531
|
+
this.$input.trigger('click')
|
|
532
|
+
e.preventDefault()
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
// FILEUPLOAD PLUGIN DEFINITION
|
|
537
|
+
// ===========================
|
|
538
|
+
|
|
539
|
+
var old = $.fn.fileinput
|
|
540
|
+
|
|
541
|
+
$.fn.fileinput = function (options) {
|
|
542
|
+
return this.each(function () {
|
|
543
|
+
var $this = $(this),
|
|
544
|
+
data = $this.data('bs.fileinput')
|
|
545
|
+
if (!data) $this.data('bs.fileinput', (data = new Fileinput(this, options)))
|
|
546
|
+
if (typeof options == 'string') data[options]()
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
$.fn.fileinput.Constructor = Fileinput
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
// FILEINPUT NO CONFLICT
|
|
554
|
+
// ====================
|
|
555
|
+
|
|
556
|
+
$.fn.fileinput.noConflict = function () {
|
|
557
|
+
$.fn.fileinput = old
|
|
558
|
+
return this
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
// FILEUPLOAD DATA-API
|
|
563
|
+
// ==================
|
|
564
|
+
|
|
565
|
+
$(document).on('click.fileinput.data-api', '[data-provides="fileinput"]', function (e) {
|
|
566
|
+
var $this = $(this)
|
|
567
|
+
if ($this.data('bs.fileinput')) return
|
|
568
|
+
$this.fileinput($this.data())
|
|
569
|
+
|
|
570
|
+
var $target = $(e.target).closest('[data-dismiss="fileinput"],[data-trigger="fileinput"]');
|
|
571
|
+
if ($target.length > 0) {
|
|
572
|
+
e.preventDefault()
|
|
573
|
+
$target.trigger('click.bs.fileinput')
|
|
574
|
+
}
|
|
575
|
+
})
|
|
576
|
+
|
|
577
|
+
}(window.jQuery);
|