x-editable-rails 1.5.1 → 1.5.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -13
- data/lib/x-editable-rails/version.rb +2 -2
- data/lib/x-editable-rails/view_helpers.rb +66 -41
- data/vendor/assets/javascripts/editable/bootstrap-editable.js +336 -203
- data/vendor/assets/javascripts/editable/bootstrap2-editable.js +308 -202
- data/vendor/assets/javascripts/editable/inputs-ext/wysihtml5-editable.js +9 -1
- data/vendor/assets/javascripts/editable/jquery-editable-poshytip.js +315 -202
- data/vendor/assets/javascripts/editable/jqueryui-editable.js +316 -203
- data/vendor/assets/javascripts/editable/rails/editable_form.js.coffee +14 -18
- data/vendor/assets/javascripts/editable/rails/error_handling.js.coffee +4 -0
- data/vendor/assets/javascripts/editable/rails.js.coffee +2 -1
- data/vendor/assets/stylesheets/editable/bootstrap-editable.scss +25 -25
- data/vendor/assets/stylesheets/editable/bootstrap2-editable.scss +25 -25
- metadata +19 -32
- /data/vendor/assets/stylesheets/editable/inputs-ext/{bootstrap-typehead.css → bootstrap-typeahead.css} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fee9739c77324495b6e7a6227d85fdb2f77c972b
|
4
|
+
data.tar.gz: fd6565d1908e346778674f1f42f95f235c335f01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d3c95a332e7da5252af57f86fb0ae39d171566d7f616b09f9d691073fbd1051e64b53e35ff9f13dbd124f57b55901e2a2cbc3295451749f1a2997627b55ff05
|
7
|
+
data.tar.gz: d43ebe0f3957a31e1c8c6476494f869f37bd456af8878d4993363130de8b41795df1dd9012ed1948e32c1ba74fdad34af06085062a03a4e46368d0b703a6740a
|
data/README.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
# X::Editable::Rails
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/werein/x-editable-rails.svg)](https://travis-ci.org/werein/x-editable-rails) [![Code Climate](https://codeclimate.com/github/werein/x-editable-rails/badges/gpa.svg)](https://codeclimate.com/github/werein/x-editable-rails) [![Test coverage](https://codeclimate.com/github/werein/x-editable-rails/badges/coverage.svg)](https://codeclimate.com/github/werein/x-editable-rails) [![Version](https://badge.fury.io/rb/x-editable-rails.svg)](https://badge.fury.io/rb/x-editable-rails) [![Dependencies](https://gemnasium.com/werein/x-editable-rails.svg)](https://gemnasium.com/werein/x-editable-rails)
|
4
|
+
|
3
5
|
X-editable for Rails
|
4
6
|
|
7
|
+
## Live demo
|
8
|
+
|
9
|
+
Checkout live demo [here](https://x-editable-rails.herokuapp.com/?denied=true)
|
10
|
+
|
5
11
|
## Installation
|
6
12
|
|
7
13
|
Add this line to your application's Gemfile:
|
@@ -75,8 +81,8 @@ And related stylesheets:
|
|
75
81
|
|
76
82
|
### Making Things Editable
|
77
83
|
|
78
|
-
`x-editable-rails` provides a helper method in your view to make your model values editable.
|
79
|
-
By default, you need to specify the model and property that should be editable.
|
84
|
+
`x-editable-rails` provides a helper method in your view to make your model values editable.
|
85
|
+
By default, you need to specify the model and property that should be editable.
|
80
86
|
A `span` element is rendered with `data-*` attributes used by `x-editable`.
|
81
87
|
|
82
88
|
```ruby
|
@@ -120,7 +126,7 @@ classes = { "Active" => "label-success", "Disabled" => "label-default" }
|
|
120
126
|
editable @model, :enabled, source: source, classes: classes, class: "label"
|
121
127
|
```
|
122
128
|
|
123
|
-
* **nested** - Name of a nested attributes (such as [
|
129
|
+
* **nested** - Name of a nested attributes (such as [globalize](https://github.com/globalize/globalize)'s `translations`)
|
124
130
|
* **nid** - ID of the nested attribute
|
125
131
|
|
126
132
|
```ruby
|
@@ -135,18 +141,16 @@ editable @model, :enabled, source: source, classes: classes, class: "label"
|
|
135
141
|
Add a helper method to your controllers to indicate if `x-editable` should be enabled.
|
136
142
|
|
137
143
|
```ruby
|
138
|
-
def xeditable?
|
144
|
+
def xeditable? object = nil
|
139
145
|
true # Or something like current_user.xeditable?
|
140
146
|
end
|
141
147
|
```
|
142
148
|
|
143
|
-
|
149
|
+
You can use [CanCan](https://github.com/ryanb/cancan) and checks the `:edit` permission for the model being edited.
|
144
150
|
|
145
151
|
```ruby
|
146
|
-
|
147
|
-
|
148
|
-
else
|
149
|
-
... output uneditable value ...
|
152
|
+
def xeditable? object = nil
|
153
|
+
can?(:edit, object) ? true : false
|
150
154
|
end
|
151
155
|
```
|
152
156
|
|
@@ -154,14 +158,14 @@ end
|
|
154
158
|
|
155
159
|
### "Don't Repeat Yourself" Templates
|
156
160
|
|
157
|
-
To make your views cleaner, you can specify all your options for each class and attribute in a YAML configuration file.
|
161
|
+
To make your views cleaner, you can specify all your options for each class and attribute in a YAML configuration file.
|
158
162
|
Attributes where the `title` or `placeholder` are not different except maybe capitalized can be left out because they are automatically capitalized when rendered (see above).
|
159
163
|
|
160
|
-
This example uses the `MailingList` class and its attributes.
|
161
|
-
The attribute value can be a string, which is used as the `title` and `placeholder`.
|
164
|
+
This example uses the `MailingList` class and its attributes.
|
165
|
+
The attribute value can be a string, which is used as the `title` and `placeholder`.
|
162
166
|
If you want to specify other options, create a hash of options.
|
163
167
|
|
164
|
-
Install configuration file like this: `rails g x_editable_rails:install`, this step is not necessary
|
168
|
+
Install configuration file like this: `rails g x_editable_rails:install`, this step is not necessary
|
165
169
|
|
166
170
|
```yaml
|
167
171
|
class_options:
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
1
3
|
module X
|
2
4
|
module Editable
|
3
5
|
module Rails
|
@@ -16,63 +18,86 @@ module X
|
|
16
18
|
# - enumerable shorthand ['Yes', 'No', 'Maybe'] becomes { 'Yes' => 'Yes', 'No' => 'No', 'Maybe' => 'Maybe' }
|
17
19
|
# classes: a Hash of classes to add based on the value (same format and shorthands as source)
|
18
20
|
# value: override the object's value
|
19
|
-
#
|
21
|
+
#
|
20
22
|
def editable(object, method, options = {})
|
21
23
|
options = Configuration.method_options_for(object, method).deep_merge(options).with_indifferent_access
|
22
24
|
# merge data attributes for backwards-compatibility
|
23
25
|
options.merge! options.delete(:data){ Hash.new }
|
24
|
-
|
26
|
+
|
25
27
|
url = options.delete(:url){ polymorphic_path(object) }
|
26
28
|
object = object.last if object.kind_of?(Array)
|
27
29
|
value = options.delete(:value){ object.send(method) }
|
28
30
|
source = options[:source] ? format_source(options.delete(:source), value) : default_source_for(value)
|
29
31
|
classes = format_source(options.delete(:classes), value)
|
30
32
|
error = options.delete(:e)
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
html_options = options.delete(:html){ Hash.new }
|
34
|
+
|
35
|
+
if xeditable?(object)
|
36
|
+
model = object.class.model_name.param_key
|
34
37
|
nid = options.delete(:nid)
|
35
38
|
nested = options.delete(:nested)
|
36
39
|
title = options.delete(:title) do
|
37
|
-
klass = nested ? object.class.const_get(nested.to_s.
|
40
|
+
klass = nested ? object.class.const_get(nested.to_s.classify) : object.class
|
38
41
|
klass.human_attribute_name(method)
|
39
42
|
end
|
40
|
-
|
43
|
+
|
41
44
|
output_value = output_value_for(value)
|
42
|
-
css_list = options.delete(:class).to_s.split(
|
45
|
+
css_list = options.delete(:class).to_s.split(/\s+/).unshift('editable')
|
43
46
|
css_list << classes[output_value] if classes
|
44
|
-
|
47
|
+
type = options.delete(:type){ default_type_for(value) }
|
45
48
|
css = css_list.compact.uniq.join(' ')
|
46
49
|
tag = options.delete(:tag){ 'span' }
|
47
50
|
placeholder = options.delete(:placeholder){ title }
|
48
|
-
|
51
|
+
|
49
52
|
# any remaining options become data attributes
|
50
53
|
data = {
|
51
|
-
type:
|
52
|
-
model: model,
|
53
|
-
name: method,
|
54
|
-
value: output_value,
|
55
|
-
placeholder: placeholder,
|
56
|
-
classes: classes,
|
57
|
-
source: source,
|
58
|
-
url: url,
|
59
|
-
nested: nested,
|
54
|
+
type: type,
|
55
|
+
model: model,
|
56
|
+
name: method,
|
57
|
+
value: ( type == 'wysihtml5' ? Base64.encode64(output_value) : output_value ),
|
58
|
+
placeholder: placeholder,
|
59
|
+
classes: classes,
|
60
|
+
source: source,
|
61
|
+
url: url,
|
62
|
+
nested: nested,
|
60
63
|
nid: nid
|
61
|
-
}.merge(options)
|
62
|
-
|
64
|
+
}.merge(options.symbolize_keys)
|
65
|
+
|
63
66
|
data.reject!{|_, value| value.nil?}
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
|
68
|
+
html_options.update({
|
69
|
+
class: css,
|
70
|
+
title: title,
|
71
|
+
data: data
|
72
|
+
})
|
73
|
+
|
74
|
+
content_tag tag, html_options do
|
75
|
+
if %w(select checklist).include?(data[:type].to_s) && !source.is_a?(String)
|
76
|
+
source = normalize_source(source)
|
77
|
+
content = source.detect { |t| output_value == output_value_for(t[0]) }
|
78
|
+
content.present? ? content[1] : ""
|
79
|
+
else
|
80
|
+
safe_join(source_values_for(value, source), tag(:br))
|
81
|
+
end
|
67
82
|
end
|
68
83
|
else
|
69
|
-
|
70
|
-
error || source_values_for(value, source).join('<br/>').html_safe
|
84
|
+
error || safe_join(source_values_for(value, source), tag(:br))
|
71
85
|
end
|
72
86
|
end
|
73
|
-
|
87
|
+
|
74
88
|
private
|
75
|
-
|
89
|
+
|
90
|
+
def normalize_source(source)
|
91
|
+
return [] unless source
|
92
|
+
source.map do |el|
|
93
|
+
if el.is_a? Array
|
94
|
+
el
|
95
|
+
else
|
96
|
+
[el[:value], el[:text]]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
76
101
|
def output_value_for(value)
|
77
102
|
value = case value
|
78
103
|
when TrueClass
|
@@ -86,22 +111,22 @@ module X
|
|
86
111
|
else
|
87
112
|
value.to_s
|
88
113
|
end
|
89
|
-
|
90
|
-
value
|
114
|
+
|
115
|
+
value
|
91
116
|
end
|
92
|
-
|
117
|
+
|
93
118
|
def source_values_for(value, source = nil)
|
94
119
|
source ||= default_source_for value
|
95
|
-
|
120
|
+
|
96
121
|
values = Array.wrap(value)
|
97
|
-
|
98
|
-
if source
|
122
|
+
|
123
|
+
if source && ( source.first.is_a?(String) || source.kind_of?(Hash) )
|
99
124
|
values.map{|item| source[output_value_for item]}
|
100
125
|
else
|
101
126
|
values
|
102
127
|
end
|
103
128
|
end
|
104
|
-
|
129
|
+
|
105
130
|
def default_type_for(value)
|
106
131
|
case value
|
107
132
|
when TrueClass, FalseClass
|
@@ -112,14 +137,14 @@ module X
|
|
112
137
|
'text'
|
113
138
|
end
|
114
139
|
end
|
115
|
-
|
140
|
+
|
116
141
|
def default_source_for(value)
|
117
142
|
case value
|
118
143
|
when TrueClass, FalseClass
|
119
144
|
{ '1' => 'Yes', '0' => 'No' }
|
120
145
|
end
|
121
146
|
end
|
122
|
-
|
147
|
+
|
123
148
|
# helper method that take some shorthand source definitions and reformats them
|
124
149
|
def format_source(source, value)
|
125
150
|
formatted_source = case value
|
@@ -127,15 +152,15 @@ module X
|
|
127
152
|
if source.is_a?(Array) && source.first.is_a?(String) && source.size == 2
|
128
153
|
{ '1' => source[0], '0' => source[1] }
|
129
154
|
end
|
130
|
-
|
155
|
+
else
|
131
156
|
if source.is_a?(Array) && source.first.is_a?(String)
|
132
|
-
source.
|
157
|
+
source.map { |v| { value: v, text: v } }
|
133
158
|
end
|
134
159
|
end
|
135
|
-
|
160
|
+
|
136
161
|
formatted_source || source
|
137
162
|
end
|
138
|
-
|
163
|
+
|
139
164
|
end
|
140
165
|
end
|
141
166
|
end
|