email_list_field 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +89 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/email_list_field.js +14 -0
- data/app/assets/javascripts/jquery-email_list_field/email_list_field.js +374 -0
- data/app/assets/stylesheets/email_list_field.scss +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/email_list_field.gemspec +39 -0
- data/lib/email_list_field.rb +8 -0
- data/lib/email_list_field/engine.rb +6 -0
- data/lib/email_list_field/static_helpers.rb +34 -0
- data/lib/email_list_field/test_helpers.rb +23 -0
- data/lib/email_list_field/version.rb +3 -0
- data/preview.gif +0 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fa1ee5984c8e2c9c1f39aa7fcef50df89d5ac91c
|
4
|
+
data.tar.gz: 4adfebbaf27ebdbe9c4d4b9a238167ffa8b28478
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7511f8e37fcd9e2fd727446db0529977370c1779baf0d74e08f52a7feb844bfbe9e9232b0c8c0db80cb64b22cd8872a3263ec8faed136c82b78d82df54e0fb9a
|
7
|
+
data.tar.gz: 60427fea02ee47cf27ce49e48c881cc4f64f989a805ee95b5de7502cf0a2f3355ad6d2ad483c69f935853c97899c89d6734ce905b7ede0bc9f633624e1070ab9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
email_list_field
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.3.1
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Henrique Gubert
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# EmailListField
|
2
|
+
|
3
|
+
Creates editable form field for email lists using jquery and jquery-ui.
|
4
|
+
|
5
|
+
This gem is a wrapper of the [jquery-email_list_field.js](https://github.com/hsgubert/jquery-email_list_field) project, that allows you to include jquery-email_list_field.js in your Rails app, using the asset pipeline. The gem currently includes v1.1.0 of jquery-email_list_field.js.
|
6
|
+
|
7
|
+
![](https://github.com/hsgubert/email_list_field/raw/master/preview.gif)
|
8
|
+
```html
|
9
|
+
<div id="mailing_list_container"></div>
|
10
|
+
<script>
|
11
|
+
$('#mailing_list_container').emailListField();
|
12
|
+
</script>
|
13
|
+
```
|
14
|
+
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'email_list_field'
|
22
|
+
```
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install email_list_field
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
Include the jquery-email_list_field.js javascript in your `app/assets/javascripts/application.js` or `app/assets/javascripts/vendor.js`:
|
35
|
+
```
|
36
|
+
//= require email_list_field
|
37
|
+
```
|
38
|
+
And include stylesheets in your `app/assets/stylesheets/application.js` or `app/assets/stylesheets/vendor.js`::
|
39
|
+
```
|
40
|
+
*= require email_list_field
|
41
|
+
```
|
42
|
+
|
43
|
+
In your view, create an empty div and call the `emailListField()` JQuery method:
|
44
|
+
```html
|
45
|
+
<div id="mailing_list_container"></div>
|
46
|
+
<script>
|
47
|
+
$('#mailing_list_container').emailListField();
|
48
|
+
</script>
|
49
|
+
```
|
50
|
+
|
51
|
+
For a full reference on all the options available, see the [jquery-email_list_field.js page](https://github.com/hsgubert/jquery-email_list_field)
|
52
|
+
|
53
|
+
## Params Handling Method
|
54
|
+
When the user submits the form containing the email list field, an array of strings will be submitted to your controller (by default at `params[:emails]`). The problem is that these string might be either an email or a string in the format "Name <email>". There is a helper to help you treat these parameters:
|
55
|
+
```ruby
|
56
|
+
params[:emails] = [
|
57
|
+
'Name <email1@address.com>',
|
58
|
+
'email2@address.com.br',
|
59
|
+
'Compound Name <EMAIL3@Address.com.de>'
|
60
|
+
]
|
61
|
+
|
62
|
+
EmailListField.parse_email_list_params(params[:emails])
|
63
|
+
# => [
|
64
|
+
# ['Name', 'email1@address.com'],
|
65
|
+
# [nil, 'email2@address.com.br'],
|
66
|
+
# ['Compound Name', 'email3@address.com.de']
|
67
|
+
# ]
|
68
|
+
```
|
69
|
+
|
70
|
+
This helper will identify the name and the email part of the string. It will also downcase all the emails. If you don't want the emails to be downcased you can pass the `lower_email_address_case: false` option as a second parameter.
|
71
|
+
|
72
|
+
## Feature/Integration Tests
|
73
|
+
For you to be able to test the email list field behavior, you will need an integration test with javascripts enabled. We recommend the RSpec + Capybara + PhantomJS tools. To make those tests easier, the gem packages helpers to be used during testing.
|
74
|
+
|
75
|
+
To include these helpers add to your `spec/spec_helper.rb` or to you `spec/rails_helper.rb`:
|
76
|
+
```ruby
|
77
|
+
RSpec.configure do |config|
|
78
|
+
config.include EmailListField::TestHelpers, type: :feature
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Then you can use these helpers:
|
83
|
+
```ruby
|
84
|
+
fill_in_email_list_field 'mailing_list_container', with: 'some@email.com'
|
85
|
+
remove_from_email_list_field 'mailing_list_container', 'some@email.com'
|
86
|
+
```
|
87
|
+
## License
|
88
|
+
|
89
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into vendor.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require taggle-full
|
14
|
+
//= require_tree ./jquery-email_list_field
|
@@ -0,0 +1,374 @@
|
|
1
|
+
////////////////////////////////////////////////////////////////////////////////
|
2
|
+
// jquery-email_list_field.js
|
3
|
+
// Author: @hsgubert - Henrique Gubert
|
4
|
+
////////////////////////////////////////////////////////////////////////////////
|
5
|
+
|
6
|
+
// JQuery plugin. Examples:
|
7
|
+
// $('#email-list-field').emailListField();
|
8
|
+
// $('#email-list-field').emailListField({ lowerEmailAddressCase: false });
|
9
|
+
//
|
10
|
+
// For reference of available options see DEFAULT_OPTIONS definition
|
11
|
+
//
|
12
|
+
$.fn.emailListField = function(options) {
|
13
|
+
var containerId = this.attr('id');
|
14
|
+
|
15
|
+
if (!containerId) {
|
16
|
+
containerId = 'email-list-field-container';
|
17
|
+
this.attr('id', containerId);
|
18
|
+
}
|
19
|
+
|
20
|
+
return new EmailListField(containerId, options);
|
21
|
+
};
|
22
|
+
|
23
|
+
|
24
|
+
// Class definition
|
25
|
+
var EmailListField = function() {
|
26
|
+
//////////////////////////////////////////////////////////////////////////////
|
27
|
+
// Static constants
|
28
|
+
//////////////////////////////////////////////////////////////////////////////
|
29
|
+
|
30
|
+
var DEFAULT_OPTIONS = {
|
31
|
+
|
32
|
+
/**
|
33
|
+
* List of known emails for autocomplete purposes. Emails can be provided
|
34
|
+
* as is or in the "Name Lastname <email>" format
|
35
|
+
* @type {Array[String]}
|
36
|
+
*/
|
37
|
+
knownFormattedEmails: [],
|
38
|
+
|
39
|
+
/**
|
40
|
+
* List of emails that are initialized in the field. Emails can be provided
|
41
|
+
* as is or in the "Name Lastname <email>" format
|
42
|
+
* @type {Array[String]}
|
43
|
+
*/
|
44
|
+
initialEmails: [],
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Name of the input fields. One hidden input is generated for each email in list
|
48
|
+
* @type {String}
|
49
|
+
*/
|
50
|
+
inputName: 'emails[]',
|
51
|
+
|
52
|
+
/**
|
53
|
+
* If true email addresses will be downcased when added. This does not affect
|
54
|
+
* name when email is added in the "Name <email>" format.
|
55
|
+
* @type {Boolean}
|
56
|
+
*/
|
57
|
+
lowerEmailAddressCase: true,
|
58
|
+
|
59
|
+
/**
|
60
|
+
* If false emails already in list will not be added
|
61
|
+
* @type {Boolean}
|
62
|
+
*/
|
63
|
+
allowDuplicateEmails: false,
|
64
|
+
|
65
|
+
/**
|
66
|
+
* If defined, a message tooltip appears when user tries to add duplicate emails
|
67
|
+
* The message is in the format "%{email} %{duplicatedEmailMessage}"
|
68
|
+
* @type {Boolean}
|
69
|
+
*/
|
70
|
+
duplicatedEmailMessage: 'is already on this email list',
|
71
|
+
|
72
|
+
/**
|
73
|
+
* If defined, a message tooltip appears when user tries to add invalid emails
|
74
|
+
* The message is in the format "%{email} %{duplicatedEmailMessage}"
|
75
|
+
* @type {String}
|
76
|
+
*/
|
77
|
+
invalidEmailMessage: 'is not a valid email address',
|
78
|
+
|
79
|
+
/**
|
80
|
+
* The message shown as placeholder in the field when there are no emails
|
81
|
+
* @type {String}
|
82
|
+
*/
|
83
|
+
placeholderMessage: 'Insert email list here',
|
84
|
+
|
85
|
+
/**
|
86
|
+
* Function that receives both the complete tag text and only the email and
|
87
|
+
* optionally returns a string with css classes to be added to the specific
|
88
|
+
* tag. If the option lowerEmailAddressCase is set, the function will receive
|
89
|
+
* the email already downcased.
|
90
|
+
* @type {function returning String}
|
91
|
+
*/
|
92
|
+
extraTagClassFunction: function(text, email) {},
|
93
|
+
|
94
|
+
/**
|
95
|
+
* Function called after each adition or removal of email. It is passed an
|
96
|
+
* array of emails (strings) exactly as shown to the user. This callback is
|
97
|
+
* designed to do actions that depend on the current state os the email list field
|
98
|
+
* @type {function}
|
99
|
+
*/
|
100
|
+
afterChangeCallback: function(formatted_emails) {}
|
101
|
+
};
|
102
|
+
|
103
|
+
// Email validation and extraction
|
104
|
+
// Email validation regexp: not the most restrictive regexp, but it does the trick
|
105
|
+
// Obs: it allows up case characters on email because we downcase them later, depending on option lowerEmailAddressCase
|
106
|
+
var emailRegexpString = "[-a-z0-9~!$%^&*_=+}{\\'?]+(\\.[-a-z0-9~!$%^&*_=+}{\\'?]+)*@([a-z0-9_][-a-z0-9_]*(\\.[-a-z0-9_]+)*\\.([a-z][a-z]+)|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,5})?";
|
107
|
+
var EMAIL_REGEXP = new RegExp('^' + emailRegexpString + '$', 'i');
|
108
|
+
var NAME_AND_EMAIL_REGEXP = new RegExp('^[^<>]*<' + emailRegexpString + '>$', 'i');
|
109
|
+
var EMAIL_EXTRACTION_REGEXP = new RegExp('^([^<>]*)<(.+)>$');
|
110
|
+
|
111
|
+
//////////////////////////////////////////////////////////////////////////////
|
112
|
+
// Constructor
|
113
|
+
//////////////////////////////////////////////////////////////////////////////
|
114
|
+
|
115
|
+
var emailListFieldConstructor = function(containerId, options) {
|
116
|
+
this.containerId = containerId;
|
117
|
+
this.options = $.extend(DEFAULT_OPTIONS, options);
|
118
|
+
this._initAttributes();
|
119
|
+
|
120
|
+
// Taggle is the ui lib used to implement the "tagging effect" when you
|
121
|
+
// finish writting an email
|
122
|
+
this._initTaggle();
|
123
|
+
|
124
|
+
this._prepopulateTaggle();
|
125
|
+
}
|
126
|
+
|
127
|
+
//////////////////////////////////////////////////////////////////////////////
|
128
|
+
// Object public functions
|
129
|
+
//////////////////////////////////////////////////////////////////////////////
|
130
|
+
|
131
|
+
emailListFieldConstructor.prototype.addEmail = function(email_or_emails) {
|
132
|
+
this.taggleObject.add(email_or_emails);
|
133
|
+
}
|
134
|
+
|
135
|
+
emailListFieldConstructor.prototype.removeEmail = function(email) {
|
136
|
+
this.taggleObject.remove(email, true);
|
137
|
+
}
|
138
|
+
|
139
|
+
emailListFieldConstructor.prototype.clear = function() {
|
140
|
+
this.taggleObject.removeAll();
|
141
|
+
}
|
142
|
+
|
143
|
+
emailListFieldConstructor.prototype.getEmails = function() {
|
144
|
+
return this.taggleObject.getTags().values;
|
145
|
+
}
|
146
|
+
|
147
|
+
//////////////////////////////////////////////////////////////////////////////
|
148
|
+
// Object private functions
|
149
|
+
//////////////////////////////////////////////////////////////////////////////
|
150
|
+
|
151
|
+
|
152
|
+
// Initialization of necessary attributes
|
153
|
+
emailListFieldConstructor.prototype._initAttributes = function() {
|
154
|
+
// Creates array to keep track of current emails on taggle, for purposes of detecting duplicates
|
155
|
+
// We create this list to keep track of just the emails (without names)
|
156
|
+
this.emailsOnTaggle = [];
|
157
|
+
};
|
158
|
+
|
159
|
+
// Runs when user tries to add email with invalid format
|
160
|
+
// It will show a message tooltip if invalidEmailMessage is defined, otherwise does nothing
|
161
|
+
// Needs to receive taggle so it can show tooltip anchored to it
|
162
|
+
emailListFieldConstructor.prototype._onInvalidEmailCallback = function(invalidEmail) {
|
163
|
+
if (this.options.invalidEmailMessage) {
|
164
|
+
var input = this.taggleObject.getInput();
|
165
|
+
|
166
|
+
// shows tooltip for 3 seconds
|
167
|
+
$(input).
|
168
|
+
attr("title", "\"" + invalidEmail + "\" " + this.options.invalidEmailMessage).
|
169
|
+
tooltip("open");
|
170
|
+
|
171
|
+
setTimeout(function() {
|
172
|
+
$(input).
|
173
|
+
tooltip("close").
|
174
|
+
attr( "title", "" );
|
175
|
+
}, 3000);
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
// Runs when user tries to add duplicated email to list, and allowDuplicateEmails is false
|
180
|
+
// It will show a message tooltip if duplicatedEmailMessage is defined, otherwise does nothing
|
181
|
+
emailListFieldConstructor.prototype._onDuplicatedEmailsCallback = function(email) {
|
182
|
+
if (this.options.duplicatedEmailMessage) {
|
183
|
+
var input = this.taggleObject.getInput();
|
184
|
+
|
185
|
+
// shows tooltip for 3 seconds
|
186
|
+
$(input).
|
187
|
+
attr("title", "\"" + email + "\" " + this.options.duplicatedEmailMessage).
|
188
|
+
tooltip("open");
|
189
|
+
|
190
|
+
setTimeout(function() {
|
191
|
+
$(input).
|
192
|
+
tooltip("close").
|
193
|
+
attr( "title", "" );
|
194
|
+
}, 3000);
|
195
|
+
}
|
196
|
+
};
|
197
|
+
|
198
|
+
// Extracts email from either a string with an email or a string with a name
|
199
|
+
// and an email, like: Compound Name <email@domain.com>
|
200
|
+
// Returns null if format is invalid
|
201
|
+
emailListFieldConstructor.prototype._extractEmail = function(text) {
|
202
|
+
var trimmedText = text.trim();
|
203
|
+
if (EMAIL_REGEXP.test(trimmedText)) {
|
204
|
+
var email = trimmedText;
|
205
|
+
} else if (NAME_AND_EMAIL_REGEXP.test(text)) {
|
206
|
+
var email = trimmedText.match(EMAIL_EXTRACTION_REGEXP)[2];
|
207
|
+
} else {
|
208
|
+
return null;
|
209
|
+
}
|
210
|
+
|
211
|
+
return (this.options.lowerEmailAddressCase ? email.toLowerCase(): email);
|
212
|
+
};
|
213
|
+
|
214
|
+
// Pre-processes email or name + email, downcasing email address if necessary
|
215
|
+
emailListFieldConstructor.prototype._normalizeEmail = function(text) {
|
216
|
+
var newText = text.trim();
|
217
|
+
|
218
|
+
if (this.options.lowerEmailAddressCase) {
|
219
|
+
if (EMAIL_REGEXP.test(newText)) {
|
220
|
+
newText = newText.toLowerCase();
|
221
|
+
}
|
222
|
+
else {
|
223
|
+
var matchdata = newText.match(EMAIL_EXTRACTION_REGEXP);
|
224
|
+
var name = matchdata[1].trim();
|
225
|
+
var email = matchdata[2].toLowerCase().trim();
|
226
|
+
newText = name + ' <' + email + '>'
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
return newText;
|
231
|
+
};
|
232
|
+
|
233
|
+
// Checks if email is authorized to be added. It checks if email is valid and if not duplicated
|
234
|
+
emailListFieldConstructor.prototype._isEmailValidAndUnique = function(text) {
|
235
|
+
var email = this._extractEmail(text);
|
236
|
+
|
237
|
+
// prevents invalid email format
|
238
|
+
if (email == null) {
|
239
|
+
this._onInvalidEmailCallback(text);
|
240
|
+
return false;
|
241
|
+
}
|
242
|
+
|
243
|
+
// prevents duplicated email
|
244
|
+
if (this.options.allowDuplicateEmails || !this._includesEmail(email)) {
|
245
|
+
return true;
|
246
|
+
}
|
247
|
+
else {
|
248
|
+
this._onDuplicatedEmailsCallback(email);
|
249
|
+
return false;
|
250
|
+
};
|
251
|
+
}
|
252
|
+
|
253
|
+
// Checks wether email is currently in the list
|
254
|
+
emailListFieldConstructor.prototype._includesEmail = function(email) {
|
255
|
+
return this.emailsOnTaggle.indexOf(email) > -1
|
256
|
+
}
|
257
|
+
|
258
|
+
// Adds email to the list used to detect duplicates. It accepts text in the format "Name <email>" too
|
259
|
+
emailListFieldConstructor.prototype._recordEmailAdded = function(text) {
|
260
|
+
var email = this._extractEmail(text);
|
261
|
+
this.emailsOnTaggle.push(email);
|
262
|
+
}
|
263
|
+
|
264
|
+
// Removes email from the list used to detect duplicates. It accepts text in the format "Name <email>" too
|
265
|
+
emailListFieldConstructor.prototype._recordEmailRemoved = function(text) {
|
266
|
+
var email = this._extractEmail(text);
|
267
|
+
var emailIndex = this.emailsOnTaggle.indexOf(email);
|
268
|
+
if (emailIndex > -1) {
|
269
|
+
this.emailsOnTaggle.splice(emailIndex, 1);
|
270
|
+
}
|
271
|
+
}
|
272
|
+
|
273
|
+
// if add extra classes to tags, depending on the return of the options.extraTagClassFunction
|
274
|
+
emailListFieldConstructor.prototype._addExtraTagClassIfNecessary = function(text, li) {
|
275
|
+
var email = this._extractEmail(text);
|
276
|
+
var extraClasses = this.options.extraTagClassFunction(text, email);
|
277
|
+
if (extraClasses && extraClasses.length > 0) {
|
278
|
+
$(li).addClass(extraClasses);
|
279
|
+
}
|
280
|
+
}
|
281
|
+
|
282
|
+
// Checks wether email is known
|
283
|
+
emailListFieldConstructor.prototype._knowsEmail = function(email) {
|
284
|
+
return this.knownEmails.indexOf(email) > -1
|
285
|
+
}
|
286
|
+
|
287
|
+
// Initializes taggle, the lib that implements the tagging effect on the email
|
288
|
+
// list field.
|
289
|
+
emailListFieldConstructor.prototype._initTaggle = function() {
|
290
|
+
// creates scoped variable so we can acccess emailListField inside the taggle callbacks
|
291
|
+
var emailListField = this;
|
292
|
+
|
293
|
+
// adds taggle class to container
|
294
|
+
$('#' + this.containerId).addClass('taggle');
|
295
|
+
|
296
|
+
this.taggleObject = new Taggle(this.containerId, {
|
297
|
+
delimeter: new RegExp('[,;]'), // splits emails on commas and semicolons (passing regexps here is not documented on taggle, but works)
|
298
|
+
submitKeys: [44, 9, 13, 27, 186], // keycodes: 9 (tab), 13 (enter), 27 (esc), 35 (end), 186 (semicolon). Ons: cannot use 188 (comma) because it is also de key of '<', which is a necessary character for emails with name
|
299
|
+
saveOnBlur: true, // tries to save the tag when user clicks away
|
300
|
+
hiddenInputName: this.options.inputName, // how the parameters are going to be submitted
|
301
|
+
placeholder: this.options.placeholderMessage, // message to show when there are no emails on list
|
302
|
+
allowDuplicates: true, // we implement our own duplicate detection, based on the email address only
|
303
|
+
preserveCase: true, // we deal with the case separately
|
304
|
+
tabIndex: 0, // makes tab select field in form
|
305
|
+
|
306
|
+
// prepares input element to show tooltip (for validation or duplicate messages)
|
307
|
+
inputFormatter: function(input) {
|
308
|
+
$(input).tooltip({position: {my:'left top', at: 'left bottom'}});
|
309
|
+
},
|
310
|
+
|
311
|
+
// prevents invalid or duplicated emails from being added to the list
|
312
|
+
onBeforeTagAdd: function(event, tag) {
|
313
|
+
return emailListField._isEmailValidAndUnique(tag);
|
314
|
+
},
|
315
|
+
|
316
|
+
// Formats the tag, normalizing email address and adding extra classes
|
317
|
+
tagFormatter: function(li) {
|
318
|
+
var text = $(li).find('.taggle_text').text();
|
319
|
+
|
320
|
+
// trims and downcases email (even when in format Name <email>)
|
321
|
+
text = emailListField._normalizeEmail(text);
|
322
|
+
|
323
|
+
// changes li and hidden input with new text
|
324
|
+
$(li).find('.taggle_text').text(text);
|
325
|
+
$(li).find('input[type="hidden"]').val(text);
|
326
|
+
|
327
|
+
emailListField._addExtraTagClassIfNecessary(text, li);
|
328
|
+
|
329
|
+
return li;
|
330
|
+
},
|
331
|
+
|
332
|
+
// records tags that are added, so to know if new candidate tags are duplicate
|
333
|
+
onTagAdd: function(event, tag) {
|
334
|
+
emailListField._recordEmailAdded(tag);
|
335
|
+
emailListField.options.afterChangeCallback(emailListField.getEmails());
|
336
|
+
},
|
337
|
+
|
338
|
+
// remove emails from list, so we don't think it is a duplicate if added again
|
339
|
+
onTagRemove: function(event, tag) {
|
340
|
+
emailListField._recordEmailRemoved(tag);
|
341
|
+
emailListField.options.afterChangeCallback(emailListField.getEmails());
|
342
|
+
}
|
343
|
+
});
|
344
|
+
|
345
|
+
// If knownFormattedEmails has elements, activate JQueryUI autocomplete
|
346
|
+
if (this.options.knownFormattedEmails.length > 0) {
|
347
|
+
var taggle = this.taggleObject;
|
348
|
+
$(this.taggleObject.getInput()).autocomplete({
|
349
|
+
source: this.options.knownFormattedEmails,
|
350
|
+
appendTo: this.taggleObject.getContainer(),
|
351
|
+
position: { at: "left bottom", of: this.taggleObject.getContainer() },
|
352
|
+
select: function(event, data) {
|
353
|
+
event.preventDefault();
|
354
|
+
|
355
|
+
// Add the tag only when the user clicks on autocomplete. If user selects
|
356
|
+
// another way (E.g.: down + enter/tab) the text will already be added as it
|
357
|
+
// is autocompleted on the input and added by taggle automatically
|
358
|
+
if (data && data.item && event.which == 1) {
|
359
|
+
taggle.add(data.item.value);
|
360
|
+
}
|
361
|
+
}
|
362
|
+
});
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
emailListFieldConstructor.prototype._prepopulateTaggle = function() {
|
367
|
+
for (var i=0; i<this.options.initialEmails.length; i++) {
|
368
|
+
this.addEmail(this.options.initialEmails[i]);
|
369
|
+
}
|
370
|
+
}
|
371
|
+
|
372
|
+
// returns contructor and calls the function so EmailListField is defined immediately
|
373
|
+
return emailListFieldConstructor;
|
374
|
+
}();
|
@@ -0,0 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require taggle
|
12
|
+
*/
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "email_list_field"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'email_list_field/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "email_list_field"
|
8
|
+
spec.version = EmailListField::VERSION
|
9
|
+
spec.date = '2016-09-29'
|
10
|
+
spec.authors = ["Henrique Gubert"]
|
11
|
+
spec.email = ["guberthenrique@hotmail.com"]
|
12
|
+
|
13
|
+
spec.summary = %q{Produces email list fields for rails forms}
|
14
|
+
spec.description = %q{This gem provides helper functions that allows you to add email list fields to your forms in a rails app. It also provides helper functions to process the submitted data on the controllers.}
|
15
|
+
spec.homepage = "https://github.com/hsgubert/email_list_field"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
# # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# # to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
# if spec.respond_to?(:metadata)
|
21
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
22
|
+
# else
|
23
|
+
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
24
|
+
# end
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_runtime_dependency 'rails', '>= 3.2', '< 5.0'
|
32
|
+
spec.add_runtime_dependency 'taggle', '0.1.2'
|
33
|
+
spec.add_runtime_dependency 'jquery-rails', '~>4'
|
34
|
+
spec.add_runtime_dependency 'jquery-ui-rails', '~>5.0'
|
35
|
+
|
36
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
37
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
38
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module EmailListField::StaticHelpers
|
2
|
+
EMAIL_EXTRACTION_REGEXP = /^([^<>]*)<(.+)>$/
|
3
|
+
|
4
|
+
# Inputs
|
5
|
+
# => emails: an array of strings, where each string may be either an email or a "Name <email>" string
|
6
|
+
# => options:
|
7
|
+
# :lower_email_address_case [true|false] default=true
|
8
|
+
#
|
9
|
+
# Output:
|
10
|
+
# => an array of pairs [name, email], where name might be nil
|
11
|
+
#
|
12
|
+
def parse_email_list_params(emails, options={})
|
13
|
+
return [] unless emails
|
14
|
+
|
15
|
+
lower_email_address_case = (!options[:lower_email_address_case].nil? ? options[:lower_email_address_case] : true)
|
16
|
+
|
17
|
+
emails.map do |formatted_email|
|
18
|
+
stripped_formatted_email = formatted_email.strip
|
19
|
+
|
20
|
+
if matchdata = stripped_formatted_email.match(EmailListField::StaticHelpers::EMAIL_EXTRACTION_REGEXP)
|
21
|
+
parsed_email = [matchdata[1].strip, matchdata[2].strip]
|
22
|
+
else
|
23
|
+
parsed_email = [nil, stripped_formatted_email]
|
24
|
+
end
|
25
|
+
|
26
|
+
if lower_email_address_case
|
27
|
+
parsed_email[1].downcase!
|
28
|
+
end
|
29
|
+
|
30
|
+
parsed_email
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Defines helpers to be used in feature/integration tests in the target app.
|
2
|
+
# These helpers work for a RSpec + Capybara + PhantomJS test suite (javascript
|
3
|
+
# must be enabled)
|
4
|
+
#
|
5
|
+
# To include these helpers add to your spec/spec_helper.rb or to you spec/rails_helper.rb:
|
6
|
+
#
|
7
|
+
# RSpec.configure do |config|
|
8
|
+
# config.include EmailListField::TestHelpers, type: :feature
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
module EmailListField::TestHelpers
|
12
|
+
|
13
|
+
def fill_in_email_list_field(wrapper_id, options={})
|
14
|
+
with = options.delete(:with)
|
15
|
+
fill_options = options.delete(:fill_options)
|
16
|
+
find('#' + wrapper_id + ' input.taggle_input').set(with, fill_options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove_from_email_list_field(wrapper_id, formatted_email)
|
20
|
+
find('#' + wrapper_id + ' li', text: formatted_email).find('button', visible: false).trigger('click')
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/preview.gif
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: email_list_field
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Henrique Gubert
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-09-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.2'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: taggle
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.1.2
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.1.2
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: jquery-rails
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '4'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '4'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: jquery-ui-rails
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '5.0'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '5.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: bundler
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '1.12'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '1.12'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rake
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '10.0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '10.0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: rspec
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '3.0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '3.0'
|
117
|
+
description: This gem provides helper functions that allows you to add email list
|
118
|
+
fields to your forms in a rails app. It also provides helper functions to process
|
119
|
+
the submitted data on the controllers.
|
120
|
+
email:
|
121
|
+
- guberthenrique@hotmail.com
|
122
|
+
executables: []
|
123
|
+
extensions: []
|
124
|
+
extra_rdoc_files: []
|
125
|
+
files:
|
126
|
+
- ".gitignore"
|
127
|
+
- ".rspec"
|
128
|
+
- ".ruby-gemset"
|
129
|
+
- ".ruby-version"
|
130
|
+
- ".travis.yml"
|
131
|
+
- Gemfile
|
132
|
+
- LICENSE.txt
|
133
|
+
- README.md
|
134
|
+
- Rakefile
|
135
|
+
- app/assets/javascripts/email_list_field.js
|
136
|
+
- app/assets/javascripts/jquery-email_list_field/email_list_field.js
|
137
|
+
- app/assets/stylesheets/email_list_field.scss
|
138
|
+
- bin/console
|
139
|
+
- bin/setup
|
140
|
+
- email_list_field.gemspec
|
141
|
+
- lib/email_list_field.rb
|
142
|
+
- lib/email_list_field/engine.rb
|
143
|
+
- lib/email_list_field/static_helpers.rb
|
144
|
+
- lib/email_list_field/test_helpers.rb
|
145
|
+
- lib/email_list_field/version.rb
|
146
|
+
- preview.gif
|
147
|
+
homepage: https://github.com/hsgubert/email_list_field
|
148
|
+
licenses:
|
149
|
+
- MIT
|
150
|
+
metadata: {}
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
requirements: []
|
166
|
+
rubyforge_project:
|
167
|
+
rubygems_version: 2.5.1
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: Produces email list fields for rails forms
|
171
|
+
test_files: []
|