para 0.6.3 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/para/admin/job-tracker.coffee +1 -1
- data/app/assets/javascripts/para/admin/tabs.coffee +14 -8
- data/app/assets/javascripts/para/admin.js +20 -0
- data/app/assets/javascripts/para/plugins-includes.js.erb +1 -0
- data/app/assets/stylesheets/para/admin.sass +1 -0
- data/app/assets/stylesheets/para/plugins-includes.sass.erb +1 -0
- data/app/controllers/concerns/para/admin/resource_controller_concerns.rb +8 -2
- data/app/controllers/para/admin/crud_resources_controller.rb +1 -1
- data/app/controllers/para/admin/exports_controller.rb +1 -1
- data/app/controllers/para/admin/resources_controller.rb +7 -2
- data/app/decorators/para/component/base_decorator.rb +2 -2
- data/app/helpers/para/admin/pagination_helper.rb +31 -0
- data/app/helpers/para/model_helper.rb +14 -4
- data/app/models/application_record.rb +3 -0
- data/app/models/para/cache/item.rb +27 -0
- data/app/models/para/page/section.rb +0 -6
- data/app/views/para/admin/resources/_exports_menu.html.haml +2 -2
- data/app/views/para/admin/resources/_list.html.haml +1 -1
- data/app/views/para/admin/resources/_per_page_select.html.haml +10 -0
- data/app/views/para/inputs/_nested_many.html.haml +1 -1
- data/app/views/para/inputs/nested_many/_add_with_subclasses.html.haml +1 -1
- data/config/locales/fr.yml +1 -0
- data/db/migrate/20161006105728_create_para_cache_items.rb +12 -0
- data/lib/generators/para/admin_user/admin_user_generator.rb +2 -1
- data/lib/generators/para/exporter/exporter_generator.rb +1 -5
- data/lib/generators/para/exporter/templates/base_exporter.rb +18 -12
- data/lib/generators/para/exporter/templates/csv_exporter.rb +35 -11
- data/lib/generators/para/exporter/templates/xls_exporter.rb +48 -0
- data/lib/generators/para/orderable/orderable_generator.rb +1 -1
- data/lib/generators/para/page/section/section_generator.rb +1 -1
- data/lib/para/attribute_field/base.rb +4 -0
- data/lib/para/attribute_field/datetime.rb +1 -1
- data/lib/para/attribute_field/file.rb +4 -0
- data/lib/para/attribute_field/image.rb +4 -0
- data/lib/para/cache/database_store.rb +71 -0
- data/lib/para/cache.rb +11 -0
- data/lib/para/config.rb +28 -2
- data/lib/para/engine.rb +9 -14
- data/lib/para/exporter/base.rb +26 -0
- data/lib/para/exporter/csv.rb +6 -26
- data/lib/para/exporter/table.rb +23 -0
- data/lib/para/exporter/xls.rb +59 -0
- data/lib/para/exporter.rb +6 -3
- data/lib/para/ext.rb +0 -1
- data/lib/para/form_builder/containers.rb +14 -1
- data/lib/para/form_builder.rb +1 -0
- data/lib/para/importer/base.rb +2 -28
- data/lib/para/inputs/nested_many_input.rb +9 -4
- data/lib/para/job/base.rb +23 -4
- data/lib/para/logging/active_job_log_subscriber.rb +2 -0
- data/lib/para/orderable.rb +2 -2
- data/lib/para/plugins/set.rb +34 -0
- data/lib/para/plugins.rb +3 -2
- data/lib/para/routing/component_controller_constraint.rb +1 -1
- data/lib/para/routing/component_name_constraint.rb +22 -0
- data/lib/para/routing.rb +1 -0
- data/lib/para/sti/root_model.rb +4 -54
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +4 -1
- data/lib/rails/routing_mapper.rb +67 -34
- data/vendor/assets/javascripts/html5-sortable.js +142 -0
- data/vendor/assets/javascripts/jasny.bootstrap.min.js +7 -0
- data/vendor/assets/javascripts/jquery.remote-modal-form.coffee +67 -0
- data/vendor/assets/javascripts/jquery.scrollto.js +187 -0
- data/vendor/assets/stylesheets/animate.min.css +6 -0
- data/vendor/assets/stylesheets/jasny.bootstrap.min.css +7 -0
- metadata +56 -9
- data/app/assets/javascripts/para/admin.coffee +0 -19
- data/lib/para/ext/simple_form_extension.rb +0 -27
data/lib/para/sti/root_model.rb
CHANGED
@@ -4,60 +4,10 @@ module Para
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
alias_method_chain :descendants, :eager_loaded_subclasses
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
module ClassMethods
|
18
|
-
def eager_load!
|
19
|
-
return if RequestStore.store[descendants_eager_load_key]
|
20
|
-
RequestStore.store[descendants_eager_load_key] = true
|
21
|
-
|
22
|
-
models_dir = Rails.root.join('app', 'models')
|
23
|
-
|
24
|
-
Dir[models_dir.join(subclasses_dir, '*.rb')].each do |file_path|
|
25
|
-
file_name = File.basename(file_path, '.rb')
|
26
|
-
|
27
|
-
# Avoid Circular dependecy errors in development, when the first
|
28
|
-
# loaded class is not the base class. In this case, the base class
|
29
|
-
# loading is triggered by the child, so if we try to load that child
|
30
|
-
# again, Rails issues a CircularDependency error
|
31
|
-
file_load_path = File.join(File.dirname(file_path), file_name)
|
32
|
-
next if ActiveSupport::Dependencies.loading.include?(file_load_path)
|
33
|
-
|
34
|
-
# Autoload the subclass
|
35
|
-
require file_load_path
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def descendants_eager_load_key
|
42
|
-
@descendants_eager_load_key ||= [
|
43
|
-
'para', 'root_model', 'descendants_eager_loaded', name
|
44
|
-
].join(':')
|
45
|
-
end
|
46
|
-
|
47
|
-
# Allows the including class to define `.subclasses_namespace` class
|
48
|
-
# method to override the namespace and directory used to eager load the
|
49
|
-
# subclasses.
|
50
|
-
#
|
51
|
-
# Note : No error is raised if target subclasses directory does not
|
52
|
-
# exist.
|
53
|
-
#
|
54
|
-
def subclasses_namespace
|
55
|
-
@subclasses_namespace ||= name.deconstantize
|
56
|
-
end
|
57
|
-
|
58
|
-
def subclasses_dir
|
59
|
-
@subclasses_dir ||= subclasses_namespace.underscore
|
60
|
-
end
|
7
|
+
Rails.logger.warn '[Warning] Para::Sti::RootModel is deprecated and ' \
|
8
|
+
'has no effect at all on your model. Please use the :nested_many ' \
|
9
|
+
'input :subclasses option to provided a list of available ' \
|
10
|
+
'subclasses to create.'
|
61
11
|
end
|
62
12
|
end
|
63
13
|
end
|
data/lib/para/version.rb
CHANGED
data/lib/para.rb
CHANGED
@@ -9,7 +9,9 @@ require 'truncate_html'
|
|
9
9
|
require 'cocoon'
|
10
10
|
require 'cancan'
|
11
11
|
require 'request_store'
|
12
|
+
require 'spreadsheet'
|
12
13
|
require 'roo'
|
14
|
+
require 'roo-xls'
|
13
15
|
require 'activejob-status'
|
14
16
|
require 'deep_cloneable'
|
15
17
|
|
@@ -28,6 +30,7 @@ require 'para/postgres_extensions_checker'
|
|
28
30
|
|
29
31
|
require 'para/ext'
|
30
32
|
require 'para/errors'
|
33
|
+
require 'para/plugins'
|
31
34
|
require 'para/config'
|
32
35
|
require 'para/model_field_parsers'
|
33
36
|
require 'para/attribute_field'
|
@@ -55,8 +58,8 @@ module Para
|
|
55
58
|
autoload :Generators
|
56
59
|
autoload :Routing
|
57
60
|
autoload :Routes
|
58
|
-
autoload :Plugins
|
59
61
|
autoload :Breadcrumbs
|
62
|
+
autoload :Cache
|
60
63
|
autoload :Logging
|
61
64
|
end
|
62
65
|
|
data/lib/rails/routing_mapper.rb
CHANGED
@@ -15,18 +15,34 @@ module ActionDispatch
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def component(component_name, options = {}, &block)
|
18
|
-
as, controller, endpoint = component_informations_from(
|
18
|
+
as, controller, component, endpoint = component_informations_from(
|
19
19
|
component_name, options
|
20
20
|
)
|
21
21
|
|
22
22
|
actions = options.fetch(:actions, [:show])
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
imports_controller = options.fetch(:imports_controller, '/para/admin/imports')
|
25
|
+
exports_controller = options.fetch(:exports_controller, '/para/admin/exports')
|
26
|
+
|
27
|
+
|
28
|
+
constraints Para::Routing::ComponentNameConstraint.new(component) do
|
29
|
+
namespace :admin do
|
30
|
+
defaults(component: component) do
|
31
|
+
resource endpoint, controller: controller, as: as
|
32
|
+
end
|
33
|
+
|
34
|
+
scope(endpoint, as: component_name, defaults: { component: component }) do
|
35
|
+
instance_eval(&block) if block
|
36
|
+
add_extensions_for(:component)
|
37
|
+
|
38
|
+
scope ':importer' do
|
39
|
+
resources :imports, controller: imports_controller
|
40
|
+
end
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
42
|
+
scope ':exporter' do
|
43
|
+
resources :exports, controller: exports_controller
|
44
|
+
end
|
45
|
+
end
|
30
46
|
end
|
31
47
|
end
|
32
48
|
end
|
@@ -38,7 +54,7 @@ module ActionDispatch
|
|
38
54
|
options[:scope] ||= ':model'
|
39
55
|
end
|
40
56
|
|
41
|
-
as, controller, endpoint = component_informations_from(
|
57
|
+
as, controller, component, endpoint = component_informations_from(
|
42
58
|
component_name, options
|
43
59
|
)
|
44
60
|
|
@@ -49,30 +65,32 @@ module ActionDispatch
|
|
49
65
|
imports_controller = options.fetch(:imports_controller, '/para/admin/imports')
|
50
66
|
exports_controller = options.fetch(:exports_controller, '/para/admin/exports')
|
51
67
|
|
52
|
-
|
68
|
+
constraints Para::Routing::ComponentNameConstraint.new(component) do
|
53
69
|
constraints Para::Routing::ComponentControllerConstraint.new(controller) do
|
54
|
-
|
55
|
-
scope
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
70
|
+
namespace :admin do
|
71
|
+
scope(endpoint, as: as, defaults: { component: component }) do
|
72
|
+
scope options[:scope] do
|
73
|
+
resources :resources, controller: controller do
|
74
|
+
collection do
|
75
|
+
patch :order
|
76
|
+
patch :tree
|
77
|
+
end
|
78
|
+
|
79
|
+
member do
|
80
|
+
post :clone
|
81
|
+
end
|
82
|
+
|
83
|
+
instance_eval(&block) if block
|
84
|
+
add_extensions_for(:crud_component)
|
60
85
|
end
|
61
86
|
|
62
|
-
|
63
|
-
|
87
|
+
scope ':importer' do
|
88
|
+
resources :imports, controller: imports_controller
|
64
89
|
end
|
65
90
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
scope ':importer' do
|
71
|
-
resources :imports, controller: imports_controller
|
72
|
-
end
|
73
|
-
|
74
|
-
scope ':exporter' do
|
75
|
-
resources :exports, controller: exports_controller
|
91
|
+
scope ':exporter' do
|
92
|
+
resources :exports, controller: exports_controller
|
93
|
+
end
|
76
94
|
end
|
77
95
|
end
|
78
96
|
end
|
@@ -87,17 +105,29 @@ module ActionDispatch
|
|
87
105
|
options[:scope] ||= ':model'
|
88
106
|
end
|
89
107
|
|
90
|
-
as, _, endpoint = component_informations_from(
|
108
|
+
as, _, component, endpoint = component_informations_from(
|
91
109
|
component_name, options
|
92
110
|
)
|
93
111
|
|
94
112
|
controller = options.fetch(:controller, '/para/admin/form_resources')
|
113
|
+
imports_controller = options.fetch(:imports_controller, '/para/admin/imports')
|
114
|
+
exports_controller = options.fetch(:exports_controller, '/para/admin/exports')
|
95
115
|
|
96
|
-
|
116
|
+
constraints Para::Routing::ComponentNameConstraint.new(component) do
|
97
117
|
constraints Para::Routing::ComponentControllerConstraint.new(controller) do
|
98
|
-
|
99
|
-
|
100
|
-
|
118
|
+
namespace :admin do
|
119
|
+
scope(endpoint, as: as, defaults: { component: component }) do
|
120
|
+
resource :resource, controller: controller, only: [:show, :create, :update] do
|
121
|
+
add_extensions_for(:form_component)
|
122
|
+
end
|
123
|
+
|
124
|
+
scope ':importer' do
|
125
|
+
resources :imports, controller: imports_controller
|
126
|
+
end
|
127
|
+
|
128
|
+
scope ':exporter' do
|
129
|
+
resources :exports, controller: exports_controller
|
130
|
+
end
|
101
131
|
end
|
102
132
|
end
|
103
133
|
end
|
@@ -108,20 +138,23 @@ module ActionDispatch
|
|
108
138
|
|
109
139
|
def draw_plugin_routes(identifier)
|
110
140
|
routes = [
|
141
|
+
'',
|
111
142
|
Para::Plugins.module_name_for(identifier),
|
112
143
|
'Routes'
|
113
144
|
].join('::').constantize
|
114
145
|
|
115
146
|
routes.new(self).draw
|
147
|
+
# If the plugin does not define a Routes module, continue
|
148
|
+
rescue NameError
|
116
149
|
end
|
117
150
|
|
118
151
|
def component_informations_from(component_name, options)
|
119
|
-
|
152
|
+
component = options.fetch(:component, component_name.to_s)
|
120
153
|
as = options.fetch(:as, component_name)
|
121
154
|
controller = options.fetch(:controller, "#{ component_name }_component")
|
122
|
-
endpoint = "
|
155
|
+
endpoint = ":component/:component_id"
|
123
156
|
|
124
|
-
[as, controller, endpoint]
|
157
|
+
[as, controller, component, endpoint]
|
125
158
|
end
|
126
159
|
|
127
160
|
def add_extensions_for(type)
|
@@ -0,0 +1,142 @@
|
|
1
|
+
/*
|
2
|
+
* HTML5 Sortable jQuery Plugin
|
3
|
+
* https://github.com/voidberg/html5sortable
|
4
|
+
*
|
5
|
+
* Original code copyright 2012 Ali Farhadi.
|
6
|
+
* This version is mantained by Alexandru Badiu <andu@ctrlz.ro>
|
7
|
+
*
|
8
|
+
* Thanks to the following contributors: andyburke, bistoco, daemianmack, drskullster, flying-sheep, OscarGodson, Parikshit N. Samant, rodolfospalenza, ssafejava
|
9
|
+
*
|
10
|
+
* Released under the MIT license.
|
11
|
+
*/
|
12
|
+
'use strict';
|
13
|
+
|
14
|
+
(function ($) {
|
15
|
+
var dragging, draggingHeight, placeholders = $();
|
16
|
+
$.fn.sortable = function (options) {
|
17
|
+
var method = String(options);
|
18
|
+
|
19
|
+
options = $.extend({
|
20
|
+
connectWith: false,
|
21
|
+
placeholder: null,
|
22
|
+
dragImage: null
|
23
|
+
}, options);
|
24
|
+
|
25
|
+
return this.each(function () {
|
26
|
+
|
27
|
+
var index, items = $(this).children(options.items), handles = options.handle ? items.find(options.handle) : items;
|
28
|
+
|
29
|
+
if (method === 'reload') {
|
30
|
+
$(this).children(options.items).off('dragstart.h5s dragend.h5s selectstart.h5s dragover.h5s dragenter.h5s drop.h5s');
|
31
|
+
}
|
32
|
+
if (/^enable|disable|destroy$/.test(method)) {
|
33
|
+
var citems = $(this).children($(this).data('items')).attr('draggable', method === 'enable');
|
34
|
+
if (method === 'destroy') {
|
35
|
+
$(this).off('sortupdate');
|
36
|
+
$(this).removeData('opts');
|
37
|
+
citems.add(this).removeData('connectWith items')
|
38
|
+
.off('dragstart.h5s dragend.h5s dragover.h5s dragenter.h5s drop.h5s').off('sortupdate');
|
39
|
+
handles.off('selectstart.h5s');
|
40
|
+
}
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
|
44
|
+
var soptions = $(this).data('opts');
|
45
|
+
|
46
|
+
if (typeof soptions === 'undefined') {
|
47
|
+
$(this).data('opts', options);
|
48
|
+
}
|
49
|
+
else {
|
50
|
+
options = soptions;
|
51
|
+
}
|
52
|
+
|
53
|
+
var startParent, newParent;
|
54
|
+
var placeholder = ( options.placeholder === null ) ? $('<' + (/^ul|ol$/i.test(this.tagName) ? 'li' : 'div') + ' class="sortable-placeholder"/>') : $(options.placeholder).addClass('sortable-placeholder');
|
55
|
+
|
56
|
+
$(this).data('items', options.items);
|
57
|
+
placeholders = placeholders.add(placeholder);
|
58
|
+
if (options.connectWith) {
|
59
|
+
$(options.connectWith).add(this).data('connectWith', options.connectWith);
|
60
|
+
}
|
61
|
+
|
62
|
+
items.attr('role', 'option');
|
63
|
+
items.attr('aria-grabbed', 'false');
|
64
|
+
|
65
|
+
// Setup drag handles
|
66
|
+
handles.attr('draggable', 'true').not('a[href], img').on('selectstart.h5s', function() {
|
67
|
+
if (this.dragDrop) {
|
68
|
+
this.dragDrop();
|
69
|
+
}
|
70
|
+
return false;
|
71
|
+
}).end();
|
72
|
+
|
73
|
+
// Handle drag events on draggable items
|
74
|
+
items.on('dragstart.h5s', function(e) {
|
75
|
+
e.stopPropagation();
|
76
|
+
|
77
|
+
var dt = e.originalEvent.dataTransfer;
|
78
|
+
dt.effectAllowed = 'move';
|
79
|
+
dt.setData('text', '');
|
80
|
+
|
81
|
+
if (options.dragImage && dt.setDragImage) {
|
82
|
+
dt.setDragImage(options.dragImage, 0, 0);
|
83
|
+
}
|
84
|
+
|
85
|
+
index = (dragging = $(this)).addClass('sortable-dragging').attr('aria-grabbed', 'true').index();
|
86
|
+
draggingHeight = dragging.outerHeight();
|
87
|
+
startParent = $(this).parent();
|
88
|
+
dragging.parent().triggerHandler('sortstart', {item: dragging, startparent: startParent});
|
89
|
+
}).on('dragend.h5s',function () {
|
90
|
+
if (!dragging) {
|
91
|
+
return;
|
92
|
+
}
|
93
|
+
dragging.removeClass('sortable-dragging').attr('aria-grabbed', 'false').show();
|
94
|
+
placeholders.detach();
|
95
|
+
newParent = $(this).parent();
|
96
|
+
if (index !== dragging.index() || startParent.get(0) !== newParent.get(0)) {
|
97
|
+
dragging.parent().triggerHandler('sortupdate', {item: dragging, oldindex: index, startparent: startParent, endparent: newParent});
|
98
|
+
}
|
99
|
+
dragging = null;
|
100
|
+
draggingHeight = null;
|
101
|
+
}).add([this, placeholder]).on('dragover.h5s dragenter.h5s drop.h5s', function(e) {
|
102
|
+
if (!items.is(dragging) && options.connectWith !== $(dragging).parent().data('connectWith')) {
|
103
|
+
return true;
|
104
|
+
}
|
105
|
+
if (e.type === 'drop') {
|
106
|
+
e.stopPropagation();
|
107
|
+
placeholders.filter(':visible').after(dragging);
|
108
|
+
dragging.trigger('dragend.h5s');
|
109
|
+
return false;
|
110
|
+
}
|
111
|
+
e.preventDefault();
|
112
|
+
e.originalEvent.dataTransfer.dropEffect = 'move';
|
113
|
+
if (items.is(this)) {
|
114
|
+
var thisHeight = $(this).outerHeight();
|
115
|
+
if (options.forcePlaceholderSize) {
|
116
|
+
placeholder.height(draggingHeight);
|
117
|
+
}
|
118
|
+
|
119
|
+
// Check if $(this) is bigger than the draggable. If it is, we have to define a dead zone to prevent flickering
|
120
|
+
if (thisHeight > draggingHeight) {
|
121
|
+
// Dead zone?
|
122
|
+
var deadZone = thisHeight - draggingHeight, offsetTop = $(this).offset().top;
|
123
|
+
if (placeholder.index() < $(this).index() && e.originalEvent.pageY < offsetTop + deadZone) {
|
124
|
+
return false;
|
125
|
+
}
|
126
|
+
else if (placeholder.index() > $(this).index() && e.originalEvent.pageY > offsetTop + thisHeight - deadZone) {
|
127
|
+
return false;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
dragging.hide();
|
132
|
+
$(this)[placeholder.index() < $(this).index() ? 'after' : 'before'](placeholder);
|
133
|
+
placeholders.not(placeholder).detach();
|
134
|
+
} else if (!placeholders.is(this) && !$(this).children(options.items).length) {
|
135
|
+
placeholders.detach();
|
136
|
+
$(this).append(placeholder);
|
137
|
+
}
|
138
|
+
return false;
|
139
|
+
});
|
140
|
+
});
|
141
|
+
};
|
142
|
+
})(jQuery);
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*!
|
2
|
+
* Jasny Bootstrap v3.1.0 (http://jasny.github.com/bootstrap)
|
3
|
+
* Copyright 2011-2014 Arnold Daniels.
|
4
|
+
* Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE)
|
5
|
+
*/
|
6
|
+
|
7
|
+
+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.$element.on("click.bs.rowlink","td:not(.rowlink-skip)",a.proxy(this.click,this))};b.DEFAULTS={target:"a"},b.prototype.click=function(b){var c=a(b.currentTarget).closest("tr").find(this.options.target)[0];if(a(b.target)[0]===c)return;b.preventDefault();if(c.click)c.click();else if(document.createEvent){var d=document.createEvent("MouseEvents");d.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),c.dispatchEvent(d)}};var c=a.fn.rowlink;a.fn.rowlink=function(c){return this.each(function(){var d=a(this),e=d.data("bs.rowlink");e||d.data("bs.rowlink",e=new b(this,c))})},a.fn.rowlink.Constructor=b,a.fn.rowlink.noConflict=function(){return a.fn.rowlink=c,this},a(document).on("click.bs.rowlink.data-api",'[data-link="row"]',function(b){if(a(b.target).closest(".rowlink-skip").length!==0)return;var c=a(this);if(c.data("bs.rowlink"))return;c.rowlink(c.data()),a(b.target).trigger("click.bs.rowlink")})}(window.jQuery),+function(a){"use strict";var b=window.orientation!==undefined,c=navigator.userAgent.toLowerCase().indexOf("android")>-1,d=window.navigator.appName=="Microsoft Internet Explorer",e=function(b,d){if(c)return;this.$element=a(b),this.options=a.extend({},e.DEFAULTS,d),this.mask=String(this.options.mask),this.init(),this.listen(),this.checkVal()};e.DEFAULTS={mask:"",placeholder:"_",definitions:{9:"[0-9]",a:"[A-Za-z]",w:"[A-Za-z0-9]","*":"."}},e.prototype.init=function(){var b=this.options.definitions,c=this.mask.length;this.tests=[],this.partialPosition=this.mask.length,this.firstNonMaskPos=null,a.each(this.mask.split(""),a.proxy(function(a,d){d=="?"?(c--,this.partialPosition=a):b[d]?(this.tests.push(new RegExp(b[d])),this.firstNonMaskPos===null&&(this.firstNonMaskPos=this.tests.length-1)):this.tests.push(null)},this)),this.buffer=a.map(this.mask.split(""),a.proxy(function(a,c){if(a!="?")return b[a]?this.options.placeholder:a},this)),this.focusText=this.$element.val(),this.$element.data("rawMaskFn",a.proxy(function(){return a.map(this.buffer,function(a,b){return this.tests[b]&&a!=this.options.placeholder?a:null}).join("")},this))},e.prototype.listen=function(){if(this.$element.attr("readonly"))return;var b=(d?"paste":"input")+".mask";this.$element.on("unmask.bs.inputmask",a.proxy(this.unmask,this)).on("focus.bs.inputmask",a.proxy(this.focusEvent,this)).on("blur.bs.inputmask",a.proxy(this.blurEvent,this)).on("keydown.bs.inputmask",a.proxy(this.keydownEvent,this)).on("keypress.bs.inputmask",a.proxy(this.keypressEvent,this)).on(b,a.proxy(this.pasteEvent,this))},e.prototype.caret=function(a,b){if(this.$element.length===0)return;if(typeof a=="number")return b=typeof b=="number"?b:a,this.$element.each(function(){if(this.setSelectionRange)this.setSelectionRange(a,b);else if(this.createTextRange){var c=this.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select()}});if(this.$element[0].setSelectionRange)a=this.$element[0].selectionStart,b=this.$element[0].selectionEnd;else if(document.selection&&document.selection.createRange){var c=document.selection.createRange();a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length}return{begin:a,end:b}},e.prototype.seekNext=function(a){var b=this.mask.length;while(++a<=b&&!this.tests[a]);return a},e.prototype.seekPrev=function(a){while(--a>=0&&!this.tests[a]);return a},e.prototype.shiftL=function(a,b){var c=this.mask.length;if(a<0)return;for(var d=a,e=this.seekNext(b);d<c;d++)if(this.tests[d]){if(e<c&&this.tests[d].test(this.buffer[e]))this.buffer[d]=this.buffer[e],this.buffer[e]=this.options.placeholder;else break;e=this.seekNext(e)}this.writeBuffer(),this.caret(Math.max(this.firstNonMaskPos,a))},e.prototype.shiftR=function(a){var b=this.mask.length;for(var c=a,d=this.options.placeholder;c<b;c++)if(this.tests[c]){var e=this.seekNext(c),f=this.buffer[c];this.buffer[c]=d;if(e<b&&this.tests[e].test(f))d=f;else break}},e.prototype.unmask=function(){this.$element.unbind(".mask").removeData("inputmask")},e.prototype.focusEvent=function(){this.focusText=this.$element.val();var a=this.mask.length,b=this.checkVal();this.writeBuffer();var c=this,d=function(){b==a?c.caret(0,b):c.caret(b)};d(),setTimeout(d,50)},e.prototype.blurEvent=function(){this.checkVal(),this.$element.val()!==this.focusText&&this.$element.trigger("change")},e.prototype.keydownEvent=function(a){var c=a.which;if(c==8||c==46||b&&c==127){var d=this.caret(),e=d.begin,f=d.end;return f-e===0&&(e=c!=46?this.seekPrev(e):f=this.seekNext(e-1),f=c==46?this.seekNext(f):f),this.clearBuffer(e,f),this.shiftL(e,f-1),!1}if(c==27)return this.$element.val(this.focusText),this.caret(0,this.checkVal()),!1},e.prototype.keypressEvent=function(a){var b=this.mask.length,c=a.which,d=this.caret();if(a.ctrlKey||a.altKey||a.metaKey||c<32)return!0;if(c){d.end-d.begin!==0&&(this.clearBuffer(d.begin,d.end),this.shiftL(d.begin,d.end-1));var e=this.seekNext(d.begin-1);if(e<b){var f=String.fromCharCode(c);if(this.tests[e].test(f)){this.shiftR(e),this.buffer[e]=f,this.writeBuffer();var g=this.seekNext(e);this.caret(g)}}return!1}},e.prototype.pasteEvent=function(){var a=this;setTimeout(function(){a.caret(a.checkVal(!0))},0)},e.prototype.clearBuffer=function(a,b){var c=this.mask.length;for(var d=a;d<b&&d<c;d++)this.tests[d]&&(this.buffer[d]=this.options.placeholder)},e.prototype.writeBuffer=function(){return this.$element.val(this.buffer.join("")).val()},e.prototype.checkVal=function(a){var b=this.mask.length,c=this.$element.val(),d=-1;for(var e=0,f=0;e<b;e++)if(this.tests[e]){this.buffer[e]=this.options.placeholder;while(f++<c.length){var g=c.charAt(f-1);if(this.tests[e].test(g)){this.buffer[e]=g,d=e;break}}if(f>c.length)break}else this.buffer[e]==c.charAt(f)&&e!=this.partialPosition&&(f++,d=e);if(!a&&d+1<this.partialPosition)this.$element.val(""),this.clearBuffer(0,b);else if(a||d+1>=this.partialPosition)this.writeBuffer(),a||this.$element.val(this.$element.val().substring(0,d+1));return this.partialPosition?e:this.firstNonMaskPos};var f=a.fn.inputmask;a.fn.inputmask=function(b){return this.each(function(){var c=a(this),d=c.data("bs.inputmask");d||c.data("bs.inputmask",d=new e(this,b))})},a.fn.inputmask.Constructor=e,a.fn.inputmask.noConflict=function(){return a.fn.inputmask=f,this},a(document).on("focus.bs.inputmask.data-api","[data-mask]",function(b){var c=a(this);if(c.data("bs.inputmask"))return;c.inputmask(c.data())})}(window.jQuery),+function(a){"use strict";var b=window.navigator.appName=="Microsoft Internet Explorer",c=function(b,c){this.$element=a(b),this.$input=this.$element.find(":file");if(this.$input.length===0)return;this.name=this.$input.attr("name")||c.name,this.$hidden=this.$element.find('input[type=hidden][name="'+this.name+'"]'),this.$hidden.length===0&&(this.$hidden=a('<input type="hidden">').insertBefore(this.$input)),this.$preview=this.$element.find(".fileinput-preview");var d=this.$preview.css("height");this.$preview.css("display")!=="inline"&&d!=="0px"&&d!=="none"&&this.$preview.css("line-height",d),this.original={exists:this.$element.hasClass("fileinput-exists"),preview:this.$preview.html(),hiddenVal:this.$hidden.val()},this.listen()};c.prototype.listen=function(){this.$input.on("change.bs.fileinput",a.proxy(this.change,this)),a(this.$input[0].form).on("reset.bs.fileinput",a.proxy(this.reset,this)),this.$element.find('[data-trigger="fileinput"]').on("click.bs.fileinput",a.proxy(this.trigger,this)),this.$element.find('[data-dismiss="fileinput"]').on("click.bs.fileinput",a.proxy(this.clear,this))},c.prototype.change=function(b){var c=b.target.files===undefined?b.target&&b.target.value?[{name:b.target.value.replace(/^.+\\/,"")}]:[]:b.target.files;b.stopPropagation();if(c.length===0){this.clear();return}this.$hidden.val(""),this.$hidden.attr("name",""),this.$input.attr("name",this.name);var d=c[0];if(this.$preview.length>0&&(typeof d.type!="undefined"?d.type.match(/^image\/(gif|png|jpeg)$/):d.name.match(/\.(gif|png|jpe?g)$/i))&&typeof FileReader!="undefined"){var e=new FileReader,f=this.$preview,g=this.$element;e.onload=function(b){var e=a("<img>");e[0].src=b.target.result,c[0].result=b.target.result,g.find(".fileinput-filename").text(d.name),f.css("max-height")!="none"&&e.css("max-height",parseInt(f.css("max-height"),10)-parseInt(f.css("padding-top"),10)-parseInt(f.css("padding-bottom"),10)-parseInt(f.css("border-top"),10)-parseInt(f.css("border-bottom"),10)),f.html(e),g.addClass("fileinput-exists").removeClass("fileinput-new"),g.trigger("change.bs.fileinput",c)},e.readAsDataURL(d)}else this.$element.find(".fileinput-filename").text(d.name),this.$preview.text(d.name),this.$element.addClass("fileinput-exists").removeClass("fileinput-new"),this.$element.trigger("change.bs.fileinput")},c.prototype.clear=function(a){a&&a.preventDefault(),this.$hidden.val(""),this.$hidden.attr("name",this.name),this.$input.attr("name","");if(b){var c=this.$input.clone(!0);this.$input.after(c),this.$input.remove(),this.$input=c}else this.$input.val("");this.$preview.html(""),this.$element.find(".fileinput-filename").text(""),this.$element.addClass("fileinput-new").removeClass("fileinput-exists"),a!==undefined&&(this.$input.trigger("change"),this.$element.trigger("clear.bs.fileinput"))},c.prototype.reset=function(){this.clear(),this.$hidden.val(this.original.hiddenVal),this.$preview.html(this.original.preview),this.$element.find(".fileinput-filename").text(""),this.original.exists?this.$element.addClass("fileinput-exists").removeClass("fileinput-new"):this.$element.addClass("fileinput-new").removeClass("fileinput-exists"),this.$element.trigger("reset.bs.fileinput")},c.prototype.trigger=function(a){this.$input.trigger("click"),a.preventDefault()};var d=a.fn.fileinput;a.fn.fileinput=function(b){return this.each(function(){var d=a(this),e=d.data("bs.fileinput");e||d.data("bs.fileinput",e=new c(this,b)),typeof b=="string"&&e[b]()})},a.fn.fileinput.Constructor=c,a.fn.fileinput.noConflict=function(){return a.fn.fileinput=d,this},a(document).on("click.fileinput.data-api",'[data-provides="fileinput"]',function(b){var c=a(this);if(c.data("bs.fileinput"))return;c.fileinput(c.data());var d=a(b.target).closest('[data-dismiss="fileinput"],[data-trigger="fileinput"]');d.length>0&&(b.preventDefault(),d.trigger("click.bs.fileinput"))})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.state=null,this.placement=null,this.options.recalc&&(this.calcClone(),a(window).on("resize",a.proxy(this.recalc,this))),this.options.autohide&&a(document).on("click",a.proxy(this.autohide,this)),this.options.toggle&&this.toggle(),this.options.disablescrolling&&(this.options.disableScrolling=this.options.disablescrolling,delete this.options.disablescrolling)};b.DEFAULTS={toggle:!0,placement:"auto",autohide:!0,recalc:!0,disableScrolling:!0},b.prototype.offset=function(){switch(this.placement){case"left":case"right":return this.$element.outerWidth();case"top":case"bottom":return this.$element.outerHeight()}},b.prototype.calcPlacement=function(){function e(a,b){if(d.css(b)==="auto")return a;if(d.css(a)==="auto")return b;var c=parseInt(d.css(a),10),e=parseInt(d.css(b),10);return c>e?b:a}if(this.options.placement!=="auto"){this.placement=this.options.placement;return}this.$element.hasClass("in")||this.$element.css("visiblity","hidden !important").addClass("in");var b=a(window).width()/this.$element.width(),c=a(window).height()/this.$element.height(),d=this.$element;this.placement=b>=c?e("left","right"):e("top","bottom"),this.$element.css("visibility")==="hidden !important"&&this.$element.removeClass("in").css("visiblity","")},b.prototype.opposite=function(a){switch(a){case"top":return"bottom";case"left":return"right";case"bottom":return"top";case"right":return"left"}},b.prototype.getCanvasElements=function(){var b=this.options.canvas?a(this.options.canvas):this.$element,c=b.find("*").filter(function(){return a(this).css("position")==="fixed"}).not(this.options.exclude);return b.add(c)},b.prototype.slide=function(b,c,d){if(!a.support.transition){var e={};return e[this.placement]="+="+c,b.animate(e,350,d)}var f=this.placement,g=this.opposite(f);b.each(function(){a(this).css(f)!=="auto"&&a(this).css(f,(parseInt(a(this).css(f),10)||0)+c),a(this).css(g)!=="auto"&&a(this).css(g,(parseInt(a(this).css(g),10)||0)-c)}),this.$element.one(a.support.transition.end,d).emulateTransitionEnd(350)},b.prototype.disableScrolling=function(){var b=a("body").width(),c="padding-"+this.opposite(this.placement);a("body").data("offcanvas-style")===undefined&&a("body").data("offcanvas-style",a("body").attr("style")||""),a("body").css("overflow","hidden");if(a("body").width()>b){var d=parseInt(a("body").css(c),10)+a("body").width()-b;setTimeout(function(){a("body").css(c,d)},1)}},b.prototype.show=function(){if(this.state)return;var b=a.Event("show.bs.offcanvas");this.$element.trigger(b);if(b.isDefaultPrevented())return;this.state="slide-in",this.calcPlacement();var c=this.getCanvasElements(),d=this.placement,e=this.opposite(d),f=this.offset();c.index(this.$element)!==-1&&(a(this.$element).data("offcanvas-style",a(this.$element).attr("style")||""),this.$element.css(d,-1*f),this.$element.css(d)),c.addClass("canvas-sliding").each(function(){a(this).data("offcanvas-style")===undefined&&a(this).data("offcanvas-style",a(this).attr("style")||""),a(this).css("position")==="static"&&a(this).css("position","relative"),(a(this).css(d)==="auto"||a(this).css(d)==="0px")&&(a(this).css(e)==="auto"||a(this).css(e)==="0px")&&a(this).css(d,0)}),this.options.disableScrolling&&this.disableScrolling();var g=function(){if(this.state!="slide-in")return;this.state="slid",c.removeClass("canvas-sliding").addClass("canvas-slid"),this.$element.trigger("shown.bs.offcanvas")};setTimeout(a.proxy(function(){this.$element.addClass("in"),this.slide(c,f,a.proxy(g,this))},this),1)},b.prototype.hide=function(b){if(this.state!=="slid")return;var c=a.Event("hide.bs.offcanvas");this.$element.trigger(c);if(c.isDefaultPrevented())return;this.state="slide-out";var d=a(".canvas-slid"),e=this.placement,f=-1*this.offset(),g=function(){if(this.state!="slide-out")return;this.state=null,this.placement=null,this.$element.removeClass("in"),d.removeClass("canvas-sliding"),d.add(this.$element).add("body").each(function(){a(this).attr("style",a(this).data("offcanvas-style")).removeData("offcanvas-style")}),this.$element.trigger("hidden.bs.offcanvas")};d.removeClass("canvas-slid").addClass("canvas-sliding"),setTimeout(a.proxy(function(){this.slide(d,f,a.proxy(g,this))},this),1)},b.prototype.toggle=function(){if(this.state==="slide-in"||this.state==="slide-out")return;this[this.state==="slid"?"hide":"show"]()},b.prototype.calcClone=function(){this.$calcClone=this.$element.clone().html("").addClass("offcanvas-clone").removeClass("in").appendTo(a("body"))},b.prototype.recalc=function(){if(this.$calcClone.css("display")==="none"||this.state!=="slid"&&this.state!=="slide-in")return;this.state=null,this.placement=null;var b=this.getCanvasElements();this.$element.removeClass("in"),b.removeClass("canvas-slid"),b.add(this.$element).add("body").each(function(){a(this).attr("style",a(this).data("offcanvas-style")).removeData("offcanvas-style")})},b.prototype.autohide=function(b){a(b.target).closest(this.$element).length===0&&this.hide()};var c=a.fn.offcanvas;a.fn.offcanvas=function(c){return this.each(function(){var d=a(this),e=d.data("bs.offcanvas"),f=a.extend({},b.DEFAULTS,d.data(),typeof c=="object"&&c);e||d.data("bs.offcanvas",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.offcanvas.Constructor=b,a.fn.offcanvas.noConflict=function(){return a.fn.offcanvas=c,this},a(document).on("click.bs.offcanvas.data-api","[data-toggle=offcanvas]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.offcanvas"),h=g?"toggle":c.data();b.stopPropagation(),g?g.toggle():f.offcanvas(h)})}(window.jQuery),+function(a){function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(a.style[c]!==undefined)return{end:b[c]};return!1}"use strict";if(a.support.transition!==undefined)return;a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()})}(window.jQuery)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Allows to handle a form in a modal with rails' jquery-ujs remote links and
|
2
|
+
# forms feature, without having to write any extra javascript
|
3
|
+
#
|
4
|
+
class @RemoteModalForm extends Vertebra.View
|
5
|
+
events:
|
6
|
+
'ajax:success form[data-remote]': 'formSuccess'
|
7
|
+
'ajax:success a[data-remote]': 'pageLoaded'
|
8
|
+
'ajax:error [data-remote]': 'formError'
|
9
|
+
'hidden.bs.modal': 'modalHidden'
|
10
|
+
'hide.bs.modal': 'modalHide'
|
11
|
+
|
12
|
+
initialize: (options = {}) ->
|
13
|
+
{ modalMarkup, @$link, refreshOnClose } = options
|
14
|
+
@replaceModalWith(modalMarkup)
|
15
|
+
@refreshOnClose = if refreshOnClose? then refreshOnClose else @$link?.data('refresh-on-close')
|
16
|
+
@trigger('shown')
|
17
|
+
|
18
|
+
formSuccess: (e, response) ->
|
19
|
+
@formDidSuccess = true
|
20
|
+
@handleModalResponse(response)
|
21
|
+
@trigger('success')
|
22
|
+
|
23
|
+
formError: (e, jqXHR) ->
|
24
|
+
@replaceModalWith(jqXHR.responseText)
|
25
|
+
@trigger('error')
|
26
|
+
|
27
|
+
pageLoaded: (e, response) ->
|
28
|
+
@handleModalResponse(response)
|
29
|
+
|
30
|
+
handleModalResponse: (response) ->
|
31
|
+
if response and $.trim(response).length
|
32
|
+
@replaceModalWith(response)
|
33
|
+
else
|
34
|
+
@hideModal()
|
35
|
+
|
36
|
+
replaceModalWith: (modalMarkup) ->
|
37
|
+
@hideModal()
|
38
|
+
@setElement($(modalMarkup).appendTo('body').modal())
|
39
|
+
@$el.data('remote-modal-form', this)
|
40
|
+
@showModal()
|
41
|
+
|
42
|
+
showModal: ->
|
43
|
+
@$el.simpleForm?()
|
44
|
+
|
45
|
+
hideModal: (options = {}) ->
|
46
|
+
@$el?.modal('hide')
|
47
|
+
|
48
|
+
modalHide: (e) ->
|
49
|
+
@refreshPage()
|
50
|
+
|
51
|
+
modalHidden: (e) ->
|
52
|
+
$(e.currentTarget).remove()
|
53
|
+
@trigger('hide')
|
54
|
+
@trigger('close') if @$el[0] is $(e.currentTarget)[0]
|
55
|
+
|
56
|
+
refreshPage: ->
|
57
|
+
Turbolinks.reloadPage() if @refreshOnClose and @formDidSuccess
|
58
|
+
|
59
|
+
trigger: (event, args...) ->
|
60
|
+
super(event, args...)
|
61
|
+
@$el.trigger("remote-modal-form:#{ event }", args)
|
62
|
+
|
63
|
+
# Lazy initialization when the link target is loaded
|
64
|
+
#
|
65
|
+
$(document).on 'page:change turbolinks:load', ->
|
66
|
+
$('body').on 'ajax:success', '[data-remote-modal-form]', (e, response) ->
|
67
|
+
new RemoteModalForm(modalMarkup: response, $link: $(e.currentTarget))
|