abracadabra 1.0.5 → 1.0.6
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/README.md +64 -8
- data/app/assets/javascripts/abracadabra.js +169 -15
- data/app/assets/stylesheets/abracadabra.css +9 -8
- data/app/helpers/abracadabra/rails/view_helper.rb +32 -1
- data/lib/abracadabra/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 213cf8616712fda20832054f530234d2026ee52a
|
4
|
+
data.tar.gz: 8a14ef87204cb4ba575ce6902b0a280518fe940f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62807428994753c30a7287ff7f6d541963778d5a5b526d16ae5dc7d6b4e2185b783841b4ab2ba0611c1e53ad5edec2d49e365399c2655e8c9e04d3059dd6f657
|
7
|
+
data.tar.gz: 593595d4f1e71c4b3b435d9a3d05841bc65cc1798ed39535a8bb25dc25d75564023d96ab9fb0b1f798d51444c6df3c1af9a572e541a2d977a169d1195cb2b02e
|
data/README.md
CHANGED
@@ -53,41 +53,97 @@ It accepts the following parameters:
|
|
53
53
|
```ruby
|
54
54
|
### REQUIRED ###
|
55
55
|
path: user_path(@user)
|
56
|
-
# Specifies where the form will be submitted.
|
56
|
+
# Description: Specifies where the form will be submitted.
|
57
57
|
|
58
58
|
attribute: :name
|
59
|
-
# Specifies what attribute your text field will be updating.
|
59
|
+
# Description: Specifies what attribute your text field will be updating.
|
60
60
|
|
61
61
|
|
62
62
|
### OPTIONAL ###
|
63
63
|
class: "my-class"
|
64
|
-
# Class(es) to be added to the text input of the form. The class
|
64
|
+
# Description: Class(es) to be added to the text input of the form. The class
|
65
|
+
# "abracadabra" is added # either way.
|
65
66
|
# Default: only "abracadabra"
|
66
67
|
|
67
68
|
value: "blah"
|
68
|
-
# An alternate value, other than what object.attribute would return.
|
69
|
+
# Description: An alternate value, other than what object.attribute would return.
|
69
70
|
# Default: object.attribute
|
70
71
|
|
71
72
|
method: "patch"
|
72
|
-
# HTTP REST method to use. Use anything but "get".
|
73
|
+
# Description: HTTP REST method to use. Use anything but "get".
|
73
74
|
# Default: "patch"
|
74
75
|
|
76
|
+
buttonless: true
|
77
|
+
# Description: Removes submit and cancel buttons, submission and cancellation is then
|
78
|
+
# done through the Enter/Tab and Escape keys, respectively.
|
79
|
+
# Default: false
|
80
|
+
|
75
81
|
remote: true
|
76
|
-
# Same as link_to's `remote: true`, form submits via AJAX.
|
82
|
+
# Description: Same as link_to's `remote: true`, form submits via AJAX.
|
77
83
|
# Default: true
|
78
84
|
|
79
85
|
# IMPORTANT: `type` will be ignored if `remote = false` is used. HTML is the default
|
80
86
|
# in Rails for standard form submissions.
|
81
87
|
type: :js
|
82
|
-
# Content type -- responds to any content
|
88
|
+
# Description: Content type -- responds to any content type (:js and :script can both be
|
89
|
+
# used to respond with Javascript).
|
83
90
|
# Default: :script (:js)
|
91
|
+
|
92
|
+
# IMPORTANT: On ajax:success, this will remove the specific abracadabra instance from
|
93
|
+
# the DOM entirely.
|
94
|
+
deletable: true
|
95
|
+
# Boolean: DELETE will be submitted without a confirmation dialog
|
96
|
+
# OR
|
97
|
+
deletable: "Are you sure?"
|
98
|
+
# String: Confirmation dialog, with the string as the message, will be displayed after
|
99
|
+
# clicking the DELETE link
|
100
|
+
# Description: Puts a link to DELETE the object (obviously, it always uses DELETE as
|
101
|
+
# the HTTP verb).
|
102
|
+
# Default: false
|
103
|
+
|
104
|
+
deletable_path: user_path(@user)
|
105
|
+
# Description: Specifies where the form will be submitted.
|
106
|
+
# Default: path (uses the same path as the main form if `deletable_path` isn't declared).
|
107
|
+
|
108
|
+
# Boolean: Open the next abracadabra instance after successful form submission (main
|
109
|
+
# form, not the DELETE link's submission) by using `.abracadabra` as the selector.
|
110
|
+
tab_to_next: true
|
111
|
+
# OR
|
112
|
+
tab_to_next: ".my-class"
|
113
|
+
# IMPORTANT: If this is a class, this abracadabra instance MUST have the same class
|
114
|
+
# as well.
|
115
|
+
# String: The class or ID of the next abracadabra instance to open on succesful form
|
116
|
+
# submission. Use `.` before a class selector or `#` before a an ID selector just as you
|
117
|
+
# would when finding an element in Javascript.
|
118
|
+
# Description: Puts a link to DELETE the object (obviously, it always uses DELETE as the
|
119
|
+
# HTTP verb).
|
120
|
+
# Default: false
|
121
|
+
|
122
|
+
submit_on_blur: true
|
123
|
+
# Description: Submit form when focus leaves the input, rather than simply closing it
|
124
|
+
# out.
|
125
|
+
# Default: false
|
126
|
+
```
|
127
|
+
|
128
|
+
## Configuration
|
129
|
+
|
130
|
+
Abracadabra allows some customization. If you would like to change what icon classes are used for the `submit`, `cancel`, and `delete` icons, you can change them globally.
|
131
|
+
|
132
|
+
In any Javascript file that loads **BEFORE** abracadabra's Javascript file that you required above, change any/all of the following variables to suit your project's needs:
|
133
|
+
|
134
|
+
```javascript
|
135
|
+
abracadabraSubmitIcon = "fa fa-check"; // default
|
136
|
+
|
137
|
+
abracadabraCancelIcon = "fa fa-times"; // default
|
138
|
+
|
139
|
+
abracadabraDeleteIcon = "fa fa-times-circle-o"; // default
|
84
140
|
```
|
85
141
|
|
86
142
|
## Future & Contributing
|
87
143
|
|
88
144
|
1. I would love anyone to add date pickers and other alternate field types to this.
|
89
145
|
|
90
|
-
2. I would love the different Bootstrap classes to be overridable with an initializer (config/abracadabra.rb) so that any framework could be used. Same with the Font-Awesome button classes.
|
146
|
+
2. I would love the different Bootstrap classes to be overridable with an initializer (config/abracadabra.rb), rather than Javascript (not sure if this is even possible), so that any framework could be used. Same with the Font-Awesome button classes.
|
91
147
|
|
92
148
|
3. I would love for a `buttons: false` option to be offered that would allow only `Tab`, `Enter` and `Escape` to submit or cancel the form submission.
|
93
149
|
|
@@ -1,38 +1,134 @@
|
|
1
1
|
$(function() {
|
2
|
-
|
2
|
+
abracadabraSubmissionInProgress = false;
|
3
|
+
abracadabraDeleteMousedown = false;
|
4
|
+
|
5
|
+
function closeAbracadabra(element, destroy) {
|
3
6
|
$element = $(element);
|
4
7
|
if($element.hasClass("abracadabra-container")) {
|
5
8
|
container = $element;
|
6
9
|
} else {
|
7
10
|
container = $element.parents(".abracadabra-container");
|
8
11
|
}
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
|
13
|
+
if(destroy) {
|
14
|
+
container.siblings(".abracadabra").remove();
|
15
|
+
} else {
|
16
|
+
value = container.find(".abracadabra-input").val();
|
17
|
+
container.siblings(".abracadabra").text(value).show();
|
18
|
+
}
|
19
|
+
|
20
|
+
try {
|
21
|
+
container.remove();
|
22
|
+
} catch (error) {
|
23
|
+
if(error.name != "NotFoundError") {
|
24
|
+
throw error;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
function tabToNextAbracadabra(element, selector) {
|
30
|
+
if(selector != undefined) {
|
31
|
+
nextAbracadabra = $(selector);
|
32
|
+
|
33
|
+
/* If selector isn't an ID, find the element with the class AFTER the current element */
|
34
|
+
if (selector.indexOf("#") == -1) {
|
35
|
+
abracadabra = $(element).parents(".abracadabra-container").siblings(".abracadabra");
|
36
|
+
indexOfAbracadabra = $(selector).index(abracadabra);
|
37
|
+
nextAbracadabra = $($(selector)[indexOfAbracadabra + 1]);
|
38
|
+
}
|
39
|
+
/* /If selector isn't an ID, find the element with the class AFTER the current element */
|
40
|
+
|
41
|
+
closeAbracadabra(element, false);
|
42
|
+
nextAbracadabra.click();
|
43
|
+
} else {
|
44
|
+
closeAbracadabra(element, false);
|
45
|
+
}
|
12
46
|
}
|
13
47
|
|
48
|
+
$("body").on("submit", ".abracadabra-form", function(e) {
|
49
|
+
if(abracadabraSubmissionInProgress == true) {
|
50
|
+
e.preventDefault();
|
51
|
+
return false;
|
52
|
+
}
|
53
|
+
abracadabraSubmissionInProgress = true;
|
54
|
+
});
|
55
|
+
|
56
|
+
$("body").on("ajax:before", ".abracadabra-delete", function() {
|
57
|
+
if(abracadabraSubmissionInProgress == true) {
|
58
|
+
e.preventDefault();
|
59
|
+
return false;
|
60
|
+
}
|
61
|
+
abracadabraSubmissionInProgress = true;
|
62
|
+
});
|
63
|
+
|
64
|
+
$("body").on("mousedown", ".abracadabra-delete", function() {
|
65
|
+
abracadabraDeleteMousedown = true;
|
66
|
+
});
|
67
|
+
|
14
68
|
$("body").on("ajax:success", ".abracadabra-form", function(e) {
|
15
|
-
|
16
|
-
|
69
|
+
target = $(e.target);
|
70
|
+
|
71
|
+
/* If form is a DELETE, remove abracadabra instance, if not, call tabToNextSelector */
|
72
|
+
if(target.hasClass("abracadabra-delete")) {
|
73
|
+
closeAbracadabra(target, true);
|
74
|
+
abracadabraDeleteMousedown = false;
|
75
|
+
} else {
|
76
|
+
input = $(target).find(".abracadabra-input");
|
77
|
+
tabToNextSelector = input.data("tab-to-next-selector");
|
78
|
+
tabToNextAbracadabra(target, tabToNextSelector);
|
79
|
+
}
|
80
|
+
/* /If form is a DELETE, remove abracadabra instance, if not, call tabToNextSelector */
|
81
|
+
|
82
|
+
abracadabraSubmissionInProgress = false;
|
83
|
+
});
|
17
84
|
|
18
85
|
$("body").on("click", ".abracadabra-cancel", function() {
|
19
|
-
|
86
|
+
if(abracadabraSubmissionInProgress == false) {
|
87
|
+
closeAbracadabra(this, false);
|
88
|
+
}
|
89
|
+
});
|
90
|
+
|
91
|
+
$("body").on("blur", ".abracadabra-input", function() {
|
92
|
+
if(abracadabraSubmissionInProgress == false && abracadabraDeleteMousedown == false) {
|
93
|
+
if($(this).data("submit-on-blur") == true) {
|
94
|
+
$(this.form).submit();
|
95
|
+
} else {
|
96
|
+
closeAbracadabra(this, false);
|
97
|
+
}
|
98
|
+
}
|
20
99
|
});
|
21
100
|
|
22
101
|
$("body").on("keydown", ".abracadabra-input", function(e) {
|
23
|
-
|
102
|
+
/* Press Tab to submit (same function as Enter key) */
|
24
103
|
if (e.keyCode == 9)
|
25
104
|
{
|
26
105
|
e.preventDefault();
|
27
|
-
|
106
|
+
if(abracadabraSubmissionInProgress == false) {
|
107
|
+
$(this.form).submit();
|
108
|
+
}
|
28
109
|
}
|
110
|
+
/* /Press Tab to submit (same function as Enter key) */
|
29
111
|
|
30
|
-
|
112
|
+
/* Press Escape to cancel */
|
31
113
|
if (e.keyCode == 27)
|
32
114
|
{
|
33
115
|
e.preventDefault();
|
34
|
-
|
116
|
+
if(abracadabraSubmissionInProgress == false) {
|
117
|
+
closeAbracadabra(this, false);
|
118
|
+
}
|
35
119
|
}
|
120
|
+
/* /Press Escape to cancel */
|
121
|
+
});
|
122
|
+
|
123
|
+
|
124
|
+
$("body").on("confirm:complete", ".abracadabra-delete", function(e, response) {
|
125
|
+
/* If cancel is clicked in the deletable_confirm dialog, focus on the input */
|
126
|
+
if(response == false) {
|
127
|
+
input = $(this).parents(".abracadabra-delete-container").siblings();
|
128
|
+
inputValue = input.val();
|
129
|
+
input.focus().val("").val(inputValue);
|
130
|
+
}
|
131
|
+
/* /If cancel is clicked in the deletable_confirm dialog, focus on the input */
|
36
132
|
});
|
37
133
|
|
38
134
|
$(".abracadabra").on("click", function() {
|
@@ -43,6 +139,55 @@ $(function() {
|
|
43
139
|
formMethod = link.data("method");
|
44
140
|
remote = ((link.data("remote") == true) ? " data-remote=\"true\"" : "");
|
45
141
|
|
142
|
+
/* Check if button classes have been manually overridden elsewhere */
|
143
|
+
if(typeof abracadabraSubmitIcon == "undefined") {
|
144
|
+
abracadabraSubmitIcon = "fa fa-check";
|
145
|
+
}
|
146
|
+
|
147
|
+
if(typeof abracadabraCancelIcon == "undefined") {
|
148
|
+
abracadabraCancelIcon = "fa fa-times";
|
149
|
+
}
|
150
|
+
|
151
|
+
if(typeof abracadabraDeleteIcon == "undefined") {
|
152
|
+
abracadabraDeleteIcon = "fa fa-times-circle-o";
|
153
|
+
}
|
154
|
+
/* /Check if button classes have been manually overridden elsewhere */
|
155
|
+
|
156
|
+
/* Deletable? */
|
157
|
+
if(link.data("deletable") !== false) {
|
158
|
+
deletablePath = link.data("deletable-path");
|
159
|
+
deletableConfirm = link.data("deletable");
|
160
|
+
if(deletableConfirm === true) {
|
161
|
+
deletableConfirm = "";
|
162
|
+
} else {
|
163
|
+
deletableConfirm = " data-confirm=\"" + deletableConfirm + "\"";
|
164
|
+
}
|
165
|
+
deletable = "<span class=\"abracadabra-delete-container\"><a href=\"" + deletablePath + "\" class=\"abracadabra-delete\" data-method=\"delete\"" + deletableConfirm + remote + " rel=\"nofollow\"><i class=\"" + abracadabraDeleteIcon + "\"></i></a></span>";
|
166
|
+
} else {
|
167
|
+
deletable = "";
|
168
|
+
}
|
169
|
+
/* /Deletable? */
|
170
|
+
|
171
|
+
/* Tab to next? */
|
172
|
+
tabToNextSelector = link.data("tab-to-next");
|
173
|
+
if(tabToNextSelector !== false) {
|
174
|
+
tabToNextSelector = link.data("tab-to-next");
|
175
|
+
tabToNextSelector = " data-tab-to-next-selector=\"" + tabToNextSelector + "\"";
|
176
|
+
} else {
|
177
|
+
tabToNextSelector = "";
|
178
|
+
}
|
179
|
+
/* /Tab to next? */
|
180
|
+
|
181
|
+
/* Submit on blur? */
|
182
|
+
submitOnBlur = link.data("submit-on-blur");
|
183
|
+
if(submitOnBlur == true) {
|
184
|
+
submitOnBlur = " data-submit-on-blur=\"true\"";
|
185
|
+
} else {
|
186
|
+
submitOnBlur = "";
|
187
|
+
}
|
188
|
+
/* /Submit on blur? */
|
189
|
+
|
190
|
+
/* AJAX? */
|
46
191
|
if(remote == "") {
|
47
192
|
authToken = "<input name=\"authenticity_token\" type=\"hidden\" value=\"" + $("meta[name=\"csrf-token\"]").attr("content") + "\">";
|
48
193
|
type = "";
|
@@ -50,21 +195,30 @@ $(function() {
|
|
50
195
|
authToken = "";
|
51
196
|
type = " data-type=\"" + link.data("type") + "\"";
|
52
197
|
}
|
198
|
+
/* /AJAX? */
|
199
|
+
|
200
|
+
/* Show buttons? */
|
201
|
+
if(link.data("buttonless") == true) {
|
202
|
+
buttons = "";
|
203
|
+
} else {
|
204
|
+
buttons = "<button type=\"submit\" class=\"btn btn-primary abracadabra-submit\"><i class=\"" + abracadabraSubmitIcon + "\"></i></button><button type=\"button\" class=\"btn abracadabra-cancel\"><i class=\"" + abracadabraCancelIcon + "\"></i></button>";
|
205
|
+
}
|
206
|
+
/* /Show buttons? */
|
53
207
|
|
54
208
|
instanceClass = link.data("class");
|
55
209
|
inputValue = link.text().replace(/"|\\"/g, """);
|
56
210
|
inputId = instanceClass + "_" + attribute;
|
57
211
|
inputName = instanceClass + "[" + attribute + "]";
|
58
212
|
|
59
|
-
buttons = "<button type=\"submit\" class=\"btn btn-primary abracadabra-submit\"><i class=\"fa fa-check\"></i></button><button type=\"button\" class=\"btn abracadabra-cancel\"><i class=\"fa fa-times\"></i></button>";
|
60
213
|
openFormTag = "<form accept-charset=\"UTF-8\" action=\"" + path + "\"" + remote + type + " class=\"form-inline abracadabra-form\" method=\"post\">";
|
61
214
|
hiddenMethodTags = "<div style=\"display:none;\"><input name=\"utf8\" type=\"hidden\" value=\"✓\"><input name=\"_method\" type=\"hidden\" value=\"" + formMethod + "\">" + authToken + "</div>";
|
62
|
-
input = "<input type=\"text\" class=\"form-control abracadabra-input\" id=\"" + inputId + "\" name=\"" + inputName + "\" value=\"" + inputValue + "\">";
|
215
|
+
input = "<input type=\"text\" class=\"form-control abracadabra-input\" id=\"" + inputId + "\" name=\"" + inputName + "\" value=\"" + inputValue + "\"" + tabToNextSelector + submitOnBlur + ">";
|
63
216
|
|
64
|
-
html = "<span class=\"abracadabra-container
|
65
|
-
html += "<div class=\"control-group\"><div class=\"abracadabra-input-and-button-wrapper\"><div class=\"abracadabra-input-container\">" + input + "</div>";
|
217
|
+
html = "<span class=\"abracadabra-container\">" + openFormTag + hiddenMethodTags;
|
218
|
+
html += "<div class=\"control-group\"><div class=\"abracadabra-input-and-button-wrapper\"><div class=\"abracadabra-input-container\">" + input + deletable + "</div>";
|
66
219
|
html += "<div class=\"abracadabra-buttons\">" + buttons + "</div></div></form></span>";
|
67
220
|
|
68
221
|
link.after(html);
|
222
|
+
link.siblings(".abracadabra-container").find(".abracadabra-input").focus().val("").val(inputValue);
|
69
223
|
});
|
70
224
|
});
|
@@ -1,21 +1,22 @@
|
|
1
|
-
.abracadabra {
|
2
|
-
border-bottom: 1px dashed;
|
3
|
-
color: #428bca;
|
4
|
-
}
|
1
|
+
.abracadabra { border-bottom: 1px dashed; }
|
5
2
|
|
6
|
-
.abracadabra:hover {
|
7
|
-
text-decoration: none;
|
8
|
-
color: darken(#428bca, 10%);
|
9
|
-
}
|
3
|
+
.abracadabra:hover { text-decoration: none; }
|
10
4
|
|
11
5
|
.abracadabra-container { display: block; }
|
12
6
|
|
13
7
|
.abracadabra-container > .abracadabra-form > .control-group > .abracadabra-input-and-button-wrapper > .abracadabra-input-container {
|
14
8
|
width: 60%;
|
15
9
|
display: inline-block;
|
10
|
+
position: relative;
|
16
11
|
}
|
17
12
|
|
18
13
|
.abracadabra-container > .abracadabra-form > .control-group > .abracadabra-input-and-button-wrapper > .abracadabra-buttons {
|
19
14
|
width: 40%;
|
20
15
|
display: inline-block;
|
16
|
+
}
|
17
|
+
|
18
|
+
.abracadabra-container > .abracadabra-form > .control-group > .abracadabra-input-and-button-wrapper > .abracadabra-input-container > .abracadabra-delete-container {
|
19
|
+
position: absolute;
|
20
|
+
top: 50%;
|
21
|
+
right: 6px;
|
21
22
|
}
|
@@ -6,6 +6,21 @@ module Abracadabra
|
|
6
6
|
link_class = "#{options[:class]} abracadabra".strip
|
7
7
|
value = options[:value] || instance.send(options[:attribute])
|
8
8
|
method = options[:method] || "patch"
|
9
|
+
path = options[:path]
|
10
|
+
buttonless = options[:buttonless] || false
|
11
|
+
deletable = options[:deletable] || false
|
12
|
+
deletable_path = options[:deletable_path] || path
|
13
|
+
submit_on_blur = options[:submit_on_blur] || false
|
14
|
+
|
15
|
+
if options[:tab_to_next] || options[:tab_to_next] != false
|
16
|
+
if options[:tab_to_next] == true
|
17
|
+
tab_to_next = ".abracadabra"
|
18
|
+
else
|
19
|
+
tab_to_next = options[:tab_to_next]
|
20
|
+
end
|
21
|
+
else
|
22
|
+
tab_to_next = false
|
23
|
+
end
|
9
24
|
|
10
25
|
if !options[:remote].nil? && options[:remote] == false
|
11
26
|
remote = false
|
@@ -15,7 +30,23 @@ module Abracadabra
|
|
15
30
|
|
16
31
|
data_type = options[:type].to_s.gsub(/^j+s+$/, "script") || "script"
|
17
32
|
|
18
|
-
link_to
|
33
|
+
link_to(
|
34
|
+
value,
|
35
|
+
"javascript:void(0)",
|
36
|
+
class: link_class, method: method.to_sym,
|
37
|
+
data: {
|
38
|
+
path: path,
|
39
|
+
attribute: options[:attribute],
|
40
|
+
class: instance_class,
|
41
|
+
type: data_type.to_sym,
|
42
|
+
buttonless: buttonless,
|
43
|
+
deletable: deletable,
|
44
|
+
deletable_path: deletable_path,
|
45
|
+
tab_to_next: tab_to_next,
|
46
|
+
submit_on_blur: submit_on_blur
|
47
|
+
},
|
48
|
+
remote: remote
|
49
|
+
)
|
19
50
|
end
|
20
51
|
end
|
21
52
|
end
|
data/lib/abracadabra/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: abracadabra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Trevor Hinesley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|