in_place_edit_with_datepicker 0.0.1
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 +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/in_place_edit_with_datepicker.gemspec +24 -0
- data/lib/assets/javascripts/best_in_place.jquery-ui.js +58 -0
- data/lib/assets/javascripts/best_in_place.js +663 -0
- data/lib/assets/javascripts/best_in_place.purr.js +20 -0
- data/lib/assets/javascripts/best_in_place_datetime.js +52 -0
- data/lib/assets/javascripts/best_in_place_datetime.js.coffee +56 -0
- data/lib/best_in_place.rb +33 -0
- data/lib/best_in_place/controller_extensions.rb +25 -0
- data/lib/best_in_place/display_methods.rb +49 -0
- data/lib/best_in_place/engine.rb +8 -0
- data/lib/best_in_place/helper.rb +204 -0
- data/lib/best_in_place/railtie.rb +10 -0
- data/lib/best_in_place/test_helpers.rb +61 -0
- data/lib/best_in_place/utils.rb +29 -0
- data/lib/best_in_place/version.rb +3 -0
- data/lib/in_place_edit_with_datepicker.rb +7 -0
- data/lib/in_place_edit_with_datepicker/version.rb +3 -0
- data/vendor/assets/javascripts/jquery.autosize.js +272 -0
- data/vendor/assets/javascripts/jquery.purr.js +135 -0
- metadata +113 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
/*
|
2
|
+
* BestInPlace 3.0.0.alpha (2014)
|
3
|
+
*
|
4
|
+
* Depends:
|
5
|
+
* best_in_place.js
|
6
|
+
* jquery.purr.js
|
7
|
+
*/
|
8
|
+
/*global BestInPlaceEditor */
|
9
|
+
|
10
|
+
BestInPlaceEditor.defaults.purrErrorContainer = "<span class='bip-flash-error'></span>";
|
11
|
+
|
12
|
+
jQuery(document).on('best_in_place:error', function (event, request, error) {
|
13
|
+
'use strict';
|
14
|
+
// Display all error messages from server side validation
|
15
|
+
jQuery.each(jQuery.parseJSON(request.responseText), function (index, value) {
|
16
|
+
if (typeof value === "object") {value = index + " " + value.toString(); }
|
17
|
+
var container = jQuery(BestInPlaceEditor.defaults.purrErrorContainer).html(value);
|
18
|
+
container.purr();
|
19
|
+
});
|
20
|
+
});
|
@@ -0,0 +1,52 @@
|
|
1
|
+
(function() {
|
2
|
+
var datetime;
|
3
|
+
|
4
|
+
datetime = {
|
5
|
+
"datetime": {
|
6
|
+
activateForm: function() {
|
7
|
+
var input_elt, options, output, overrideOptions, that, _defaults;
|
8
|
+
that = this;
|
9
|
+
_defaults = {
|
10
|
+
dateFormat: "yy-mm-dd",
|
11
|
+
timeFormat: "HH:mm:ss",
|
12
|
+
parse: 'loose',
|
13
|
+
onClose: function() {
|
14
|
+
return that.update();
|
15
|
+
}
|
16
|
+
};
|
17
|
+
overrideOptions = $(this.element[0]).data('datetimepicker-options');
|
18
|
+
options = $.extend({}, _defaults, overrideOptions);
|
19
|
+
output = jQuery(document.createElement('form')).addClass('form_in_place').attr('action', 'javascript:void(0);').attr('style', 'display:inline');
|
20
|
+
input_elt = jQuery(document.createElement('input')).attr('type', 'text').attr('name', this.attributeName).attr('value', this.sanitizeValue(this.display_value));
|
21
|
+
if (this.inner_class !== null) {
|
22
|
+
input_elt.addClass(this.inner_class);
|
23
|
+
}
|
24
|
+
output.append(input_elt);
|
25
|
+
this.element.html(output);
|
26
|
+
this.setHtmlAttributes();
|
27
|
+
this.element.find('input')[0].select();
|
28
|
+
this.element.find("form").bind('submit', {
|
29
|
+
editor: this
|
30
|
+
}, BestInPlaceEditor.forms.input.submitHandler);
|
31
|
+
this.element.find("input").bind('keyup', {
|
32
|
+
editor: this
|
33
|
+
}, BestInPlaceEditor.forms.input.keyupHandler);
|
34
|
+
return this.element.find('input').datetimepicker(options).datepicker('show');
|
35
|
+
},
|
36
|
+
getValue: function() {
|
37
|
+
return this.sanitizeValue(this.element.find("input").val());
|
38
|
+
},
|
39
|
+
submitHandler: function(event) {
|
40
|
+
return event.data.editor.update();
|
41
|
+
},
|
42
|
+
keyupHandler: function(event) {
|
43
|
+
if (event.keyCode === 27) {
|
44
|
+
return event.data.editor.abort();
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
$.extend(BestInPlaceEditor.forms, datetime);
|
51
|
+
|
52
|
+
}).call(this);
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#= require best_in_place
|
2
|
+
#= require jquery-ui
|
3
|
+
#= require jquery-ui-timepicker-addon
|
4
|
+
|
5
|
+
datetime =
|
6
|
+
"datetime" :
|
7
|
+
activateForm: ->
|
8
|
+
that = this
|
9
|
+
|
10
|
+
_defaults =
|
11
|
+
dateFormat: "yy-mm-dd"
|
12
|
+
timeFormat: "HH:mm:ss"
|
13
|
+
parse: 'loose'
|
14
|
+
onClose: ->
|
15
|
+
that.update()
|
16
|
+
overrideOptions = jQuery(this.element[0]).data('datetimepicker-options')
|
17
|
+
options = $.extend {}, _defaults, overrideOptions
|
18
|
+
|
19
|
+
output = jQuery(document.createElement('form'))
|
20
|
+
.addClass('form_in_place')
|
21
|
+
.attr('action', 'javascript:void(0);')
|
22
|
+
.attr('style', 'display:inline')
|
23
|
+
input_elt = jQuery(document.createElement('input'))
|
24
|
+
.attr('type', 'text')
|
25
|
+
.attr('name', this.attributeName)
|
26
|
+
.attr('value', this.sanitizeValue(this.display_value))
|
27
|
+
|
28
|
+
if (this.inner_class != null)
|
29
|
+
input_elt.addClass(this.inner_class)
|
30
|
+
|
31
|
+
output.append(input_elt)
|
32
|
+
|
33
|
+
this.element.html(output)
|
34
|
+
this.setHtmlAttributes()
|
35
|
+
this.element.find('input')[0].select()
|
36
|
+
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler)
|
37
|
+
this.element.find("input").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler)
|
38
|
+
|
39
|
+
this.element.find('input')
|
40
|
+
.datetimepicker(options)
|
41
|
+
.datepicker('show')
|
42
|
+
,
|
43
|
+
|
44
|
+
getValue: ->
|
45
|
+
this.sanitizeValue(this.element.find("input").val())
|
46
|
+
,
|
47
|
+
|
48
|
+
submitHandler : (event) ->
|
49
|
+
event.data.editor.update()
|
50
|
+
,
|
51
|
+
|
52
|
+
keyupHandler : (event) ->
|
53
|
+
if (event.keyCode == 27)
|
54
|
+
event.data.editor.abort()
|
55
|
+
|
56
|
+
$.extend BestInPlaceEditor.forms, datetime
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
require 'action_view/railtie'
|
3
|
+
require 'action_controller/railtie'
|
4
|
+
|
5
|
+
module BestInPlace
|
6
|
+
def self.configure
|
7
|
+
@configuration ||= Configuration.new
|
8
|
+
yield @configuration if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.method_missing(method_name, *args, &block)
|
12
|
+
@configuration.respond_to?(method_name) ?
|
13
|
+
@configuration.send(method_name, *args, &block) : super
|
14
|
+
end
|
15
|
+
|
16
|
+
class Configuration
|
17
|
+
attr_accessor :container, :skip_blur
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@container = :span
|
21
|
+
@skip_blur = false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
configure
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'best_in_place/engine'
|
29
|
+
require 'best_in_place/utils'
|
30
|
+
require 'best_in_place/helper'
|
31
|
+
require 'best_in_place/railtie'
|
32
|
+
require 'best_in_place/controller_extensions'
|
33
|
+
require 'best_in_place/display_methods'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module BestInPlace
|
2
|
+
module ControllerExtensions
|
3
|
+
def respond_with_bip(obj, options = {})
|
4
|
+
obj.errors.any? ? respond_bip_error(obj) : respond_bip_ok(obj, options)
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def respond_bip_ok(obj, options = {})
|
10
|
+
param_key = options[:param] ||= BestInPlace::Utils.object_to_key(obj)
|
11
|
+
|
12
|
+
updating_attr = params[param_key].keys.first
|
13
|
+
|
14
|
+
if renderer = BestInPlace::DisplayMethods.lookup(obj.class, updating_attr)
|
15
|
+
render json: renderer.render_json(obj)
|
16
|
+
else
|
17
|
+
head :no_content
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_bip_error(obj)
|
22
|
+
render json: obj.errors.full_messages, status: :unprocessable_entity
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module BestInPlace
|
2
|
+
module DisplayMethods #:nodoc:
|
3
|
+
module_function
|
4
|
+
|
5
|
+
class Renderer < Struct.new(:opts)
|
6
|
+
def render_json(object)
|
7
|
+
case opts[:type]
|
8
|
+
when :model
|
9
|
+
{ display_as: object.send(opts[:method]) }.to_json
|
10
|
+
when :helper
|
11
|
+
value = if opts[:helper_options]
|
12
|
+
BestInPlace::ViewHelpers.send(opts[:method], object.send(opts[:attr]), opts[:helper_options])
|
13
|
+
else
|
14
|
+
BestInPlace::ViewHelpers.send(opts[:method], object.send(opts[:attr]))
|
15
|
+
end
|
16
|
+
{ display_as: value }.to_json
|
17
|
+
when :proc
|
18
|
+
{ display_as: opts[:proc].call(object.send(opts[:attr])) }.to_json
|
19
|
+
else
|
20
|
+
'{}'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@@table = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
|
26
|
+
|
27
|
+
def lookup(klass, attr)
|
28
|
+
foo = model_attributes(klass)[attr.to_s]
|
29
|
+
foo == {} ? nil : foo
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_model_method(klass, attr, display_as)
|
33
|
+
model_attributes(klass)[attr.to_s] = Renderer.new method: display_as.to_sym, type: :model
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_helper_method(klass, attr, helper_method, helper_options = nil)
|
37
|
+
model_attributes(klass)[attr.to_s] = Renderer.new method: helper_method.to_sym, type: :helper, attr: attr, helper_options: helper_options
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_helper_proc(klass, attr, helper_proc)
|
41
|
+
model_attributes(klass)[attr.to_s] = Renderer.new type: :proc, attr: attr, proc: helper_proc
|
42
|
+
end
|
43
|
+
|
44
|
+
def model_attributes(klass)
|
45
|
+
key = Utils.object_to_key(klass)
|
46
|
+
@@table[key]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
module BestInPlace
|
2
|
+
module Helper
|
3
|
+
def best_in_place(object, field, opts = {})
|
4
|
+
|
5
|
+
best_in_place_assert_arguments(opts)
|
6
|
+
type = opts[:as] || :input
|
7
|
+
field = field.to_s
|
8
|
+
|
9
|
+
options = {}
|
10
|
+
options[:data] = HashWithIndifferentAccess.new(opts[:data])
|
11
|
+
options[:data]['bip-type'] = type
|
12
|
+
options[:data]['bip-attribute'] = field
|
13
|
+
|
14
|
+
real_object = best_in_place_real_object_for object
|
15
|
+
|
16
|
+
display_value = best_in_place_build_value_for(real_object, field, opts)
|
17
|
+
|
18
|
+
value = real_object.send(field)
|
19
|
+
|
20
|
+
if opts[:collection] or type == :checkbox
|
21
|
+
collection = opts[:collection]
|
22
|
+
value = value.to_s
|
23
|
+
collection = best_in_place_default_collection if collection.blank?
|
24
|
+
collection = best_in_place_collection_builder(type, collection)
|
25
|
+
display_value = collection.flat_map{|a| a[0].to_s == value ? a[1] : nil }.compact[0]
|
26
|
+
collection = collection.to_json
|
27
|
+
options[:data]['bip-collection'] = html_escape(collection)
|
28
|
+
end
|
29
|
+
|
30
|
+
options[:class] = ['best_in_place'] + Array(opts[:class] || opts[:classes])
|
31
|
+
options[:id] = opts[:id] || BestInPlace::Utils.build_best_in_place_id(real_object, field)
|
32
|
+
|
33
|
+
pass_through_html_options(opts, options)
|
34
|
+
|
35
|
+
options[:data]['bip-activator'] = opts[:activator].presence
|
36
|
+
|
37
|
+
options[:data]['bip-html-attrs'] = opts[:html_attrs].to_json unless opts[:html_attrs].blank?
|
38
|
+
options[:data]['bip-inner-class'] = opts[:inner_class].presence
|
39
|
+
|
40
|
+
options[:data]['bip-placeholder'] = html_escape(opts[:place_holder]).presence
|
41
|
+
|
42
|
+
options[:data]['bip-object'] = opts[:param] || BestInPlace::Utils.object_to_key(real_object)
|
43
|
+
options[:data]['bip-ok-button'] = opts[:ok_button].presence
|
44
|
+
options[:data]['bip-ok-button-class'] = opts[:ok_button_class].presence
|
45
|
+
options[:data]['bip-cancel-button'] = opts[:cancel_button].presence
|
46
|
+
options[:data]['bip-cancel-button-class'] = opts[:cancel_button_class].presence
|
47
|
+
options[:data]['bip-original-content'] = html_escape(opts[:value] || value).presence
|
48
|
+
|
49
|
+
options[:data]['bip-skip-blur'] = opts.has_key?(:skip_blur) ? opts[:skip_blur].presence : BestInPlace.skip_blur
|
50
|
+
|
51
|
+
options[:data]['bip-url'] = url_for(opts[:url] || object)
|
52
|
+
|
53
|
+
options[:data]['bip-confirm'] = opts[:confirm].presence
|
54
|
+
options[:data]['bip-value'] = html_escape(value).presence
|
55
|
+
|
56
|
+
if opts[:raw]
|
57
|
+
options[:data]['bip-raw'] = 'true'
|
58
|
+
end
|
59
|
+
|
60
|
+
# delete nil keys only
|
61
|
+
options[:data].delete_if { |_, v| v.nil? }
|
62
|
+
container = opts[:container] || BestInPlace.container
|
63
|
+
content_tag(container, display_value, options, opts[:raw].blank?)
|
64
|
+
end
|
65
|
+
|
66
|
+
def best_in_place_if(condition, object, field, opts = {})
|
67
|
+
if condition
|
68
|
+
best_in_place(object, field, opts)
|
69
|
+
else
|
70
|
+
best_in_place_build_value_for best_in_place_real_object_for(object), field, opts
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def best_in_place_unless(condition, object, field, opts = {})
|
75
|
+
best_in_place_if(!condition, object, field, opts)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def pass_through_html_options(opts, options)
|
81
|
+
known_keys = [:id, :type, :nil, :classes, :collection, :data,
|
82
|
+
:activator, :cancel_button, :cancel_button_class, :html_attrs, :inner_class, :nil,
|
83
|
+
:object_name, :ok_button, :ok_button_class, :display_as, :display_with, :path, :value,
|
84
|
+
:use_confirm, :confirm, :sanitize, :raw, :helper_options, :url, :place_holder, :class,
|
85
|
+
:as, :param, :container]
|
86
|
+
uknown_keys = opts.keys - known_keys
|
87
|
+
uknown_keys.each { |key| options[key] = opts[key] }
|
88
|
+
end
|
89
|
+
|
90
|
+
def best_in_place_build_value_for(object, field, opts)
|
91
|
+
klass = object.class
|
92
|
+
if opts[:display_as]
|
93
|
+
BestInPlace::DisplayMethods.add_model_method(klass, field, opts[:display_as])
|
94
|
+
object.send(opts[:display_as]).to_s
|
95
|
+
|
96
|
+
elsif opts[:display_with].try(:is_a?, Proc)
|
97
|
+
BestInPlace::DisplayMethods.add_helper_proc(klass, field, opts[:display_with])
|
98
|
+
opts[:display_with].call(object.send(field))
|
99
|
+
|
100
|
+
elsif opts[:display_with]
|
101
|
+
BestInPlace::DisplayMethods.add_helper_method(klass, field, opts[:display_with], opts[:helper_options])
|
102
|
+
if opts[:helper_options]
|
103
|
+
BestInPlace::ViewHelpers.send(opts[:display_with], object.send(field), opts[:helper_options])
|
104
|
+
else
|
105
|
+
field_value = object.send(field)
|
106
|
+
|
107
|
+
if field_value.blank?
|
108
|
+
''
|
109
|
+
else
|
110
|
+
BestInPlace::ViewHelpers.send(opts[:display_with], field_value)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
else
|
115
|
+
object.send(field).to_s
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def best_in_place_real_object_for(object)
|
120
|
+
(object.is_a?(Array) && object.last.class.respond_to?(:model_name)) ? object.last : object
|
121
|
+
end
|
122
|
+
|
123
|
+
def best_in_place_assert_arguments(args)
|
124
|
+
best_in_place_deprecated_options(args)
|
125
|
+
|
126
|
+
if args[:display_as] && args[:display_with]
|
127
|
+
fail ArgumentError, 'Can`t use both `display_as`` and `display_with` options at the same time'
|
128
|
+
end
|
129
|
+
|
130
|
+
if args[:display_with] && !args[:display_with].is_a?(Proc) && !ViewHelpers.respond_to?(args[:display_with])
|
131
|
+
fail ArgumentError, "Can't find helper #{args[:display_with]}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def best_in_place_deprecated_options(args)
|
136
|
+
if deprecated_option = args.delete(:path)
|
137
|
+
args[:url] = deprecated_option
|
138
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :path is deprecated in favor of :url ')
|
139
|
+
end
|
140
|
+
|
141
|
+
if deprecated_option = args.delete(:object_name)
|
142
|
+
args[:param] = deprecated_option
|
143
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :object_name is deprecated in favor of :param ')
|
144
|
+
end
|
145
|
+
|
146
|
+
if deprecated_option = args.delete(:type)
|
147
|
+
args[:as] = deprecated_option
|
148
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :type is deprecated in favor of :as ')
|
149
|
+
end
|
150
|
+
|
151
|
+
if deprecated_option = args.delete(:classes)
|
152
|
+
args[:class] = deprecated_option
|
153
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :classes is deprecated in favor of :class ')
|
154
|
+
end
|
155
|
+
|
156
|
+
if deprecated_option = args.delete(:nil)
|
157
|
+
args[:place_holder] = deprecated_option
|
158
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :nil is deprecated in favor of :place_holder ')
|
159
|
+
end
|
160
|
+
|
161
|
+
if deprecated_option = args.delete(:use_confirm)
|
162
|
+
args[:confirm] = deprecated_option
|
163
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :use_confirm is deprecated in favor of :confirm ')
|
164
|
+
end
|
165
|
+
|
166
|
+
if deprecated_option = args.delete(:sanitize)
|
167
|
+
args[:raw] = !deprecated_option
|
168
|
+
ActiveSupport::Deprecation.warn('[Best_in_place] :sanitize is deprecated in favor of :raw ')
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def best_in_place_collection_builder(type, collection)
|
173
|
+
collection = case collection
|
174
|
+
when Array
|
175
|
+
if type == :checkbox
|
176
|
+
if collection.length == 2
|
177
|
+
[['false', collection[0]], ['true', collection[1]]]
|
178
|
+
else
|
179
|
+
fail ArgumentError, '[Best_in_place] :collection array should have 2 values'
|
180
|
+
end
|
181
|
+
else # :select
|
182
|
+
case collection[0]
|
183
|
+
when Array
|
184
|
+
collection
|
185
|
+
else
|
186
|
+
if collection[0].length == 2
|
187
|
+
collection.to_a
|
188
|
+
else
|
189
|
+
collection.each_with_index.map{|a,i| [i+1,a]}
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
else
|
194
|
+
collection.to_a
|
195
|
+
end
|
196
|
+
collection
|
197
|
+
end
|
198
|
+
|
199
|
+
def best_in_place_default_collection
|
200
|
+
{'true' => t(:'best_in_place.yes', default: 'Yes'),
|
201
|
+
'false' => t(:'best_in_place.no', default: 'No')}
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|