meiomask-rails 1.1.12
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.
- data/.gitignore +18 -0
- data/AUTHORS.md +1 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +4 -0
- data/LICENSE-MIT.md +22 -0
- data/README.md +25 -0
- data/Rakefile +1 -0
- data/lib/meiomask-rails.rb +6 -0
- data/meiomask-rails.gemspec +18 -0
- data/vendor/assets/javascripts/meiomask.js +771 -0
- metadata +56 -0
data/.gitignore
ADDED
data/AUTHORS.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Fábio M. Costa (http://github.com/fabiomcosta)
|
data/CONTRIBUTING.md
ADDED
data/Gemfile
ADDED
data/LICENSE-MIT.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2008-2013 Fábio M. Costa fabiomcosta@gmail.com, and contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# MeioMask::Rails
|
2
|
+
|
3
|
+
Gemified assets for [jquery.meiomask plugin](https://github.com/fabiomcosta/jquery-meiomask).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
`gem 'meiomask-rails'`
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
`$ bundle`
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
`$ gem install meiomask-rails`
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Add to your `application.js`:
|
22
|
+
|
23
|
+
`require meiomask`
|
24
|
+
|
25
|
+
And use it as the plugin documentation describes.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "meiomask-rails"
|
7
|
+
gem.version = "1.1.12"
|
8
|
+
gem.authors = ["Fabio M. Costa"]
|
9
|
+
gem.email = ["fabiomcosta@gmail.com"]
|
10
|
+
gem.description = %q{jquery.meiomask for rails.}
|
11
|
+
gem.summary = %q{jquery.meiomask for rails.}
|
12
|
+
gem.homepage = "https://github.com/fabiomcosta/jquery-meiomask"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
end
|
@@ -0,0 +1,771 @@
|
|
1
|
+
/**
|
2
|
+
* jquery.meio.mask.js
|
3
|
+
* @author: fabiomcosta
|
4
|
+
* @version: 1.1.12
|
5
|
+
*
|
6
|
+
* Created by Fabio M. Costa on 2008-09-16. Please report any bug at http://www.meiocodigo.com
|
7
|
+
*
|
8
|
+
* Copyright (c) 2008 Fabio M. Costa http://www.meiocodigo.com
|
9
|
+
*
|
10
|
+
* The MIT License (http://www.opensource.org/licenses/mit-license.php)
|
11
|
+
*
|
12
|
+
* Permission is hereby granted, free of charge, to any person
|
13
|
+
* obtaining a copy of this software and associated documentation
|
14
|
+
* files (the "Software"), to deal in the Software without
|
15
|
+
* restriction, including without limitation the rights to use,
|
16
|
+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
17
|
+
* copies of the Software, and to permit persons to whom the
|
18
|
+
* Software is furnished to do so, subject to the following
|
19
|
+
* conditions:
|
20
|
+
*
|
21
|
+
* The above copyright notice and this permission notice shall be
|
22
|
+
* included in all copies or substantial portions of the Software.
|
23
|
+
*
|
24
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
25
|
+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
26
|
+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
27
|
+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
28
|
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
29
|
+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
30
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
31
|
+
* OTHER DEALINGS IN THE SOFTWARE.
|
32
|
+
*/
|
33
|
+
|
34
|
+
(function($) {
|
35
|
+
|
36
|
+
// https://github.com/jquery/jquery-migrate/blob/master/src/core.js#L50
|
37
|
+
if (!$.browser) {
|
38
|
+
var uaMatch = function(ua) {
|
39
|
+
ua = ua.toLowerCase();
|
40
|
+
|
41
|
+
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
|
42
|
+
|
43
|
+
return match[2] || '0';
|
44
|
+
};
|
45
|
+
|
46
|
+
$.browser = {
|
47
|
+
mozilla: /mozilla/.test(navigator.userAgent.toLowerCase()) && !/webkit/.test(navigator.userAgent.toLowerCase()),
|
48
|
+
webkit: /webkit/.test(navigator.userAgent.toLowerCase()),
|
49
|
+
opera: /opera/.test(navigator.userAgent.toLowerCase()),
|
50
|
+
msie: /msie/.test(navigator.userAgent.toLowerCase()),
|
51
|
+
android: (navigator.userAgent.toLowerCase().indexOf('mozilla/5.0') > -1 && navigator.userAgent.toLowerCase().indexOf('android ') > -1 && navigator.userAgent.toLowerCase().indexOf('applewebkit') > -1),
|
52
|
+
version: uaMatch(navigator.userAgent)
|
53
|
+
};
|
54
|
+
}
|
55
|
+
|
56
|
+
var isMobile = (window.orientation != null);
|
57
|
+
|
58
|
+
// browsers like firefox2 and before and opera doesnt have the onPaste event, but the paste feature can be done with the onInput event.
|
59
|
+
var pasteEvent = (($.browser.opera || ($.browser.mozilla && parseFloat($.browser.version.substr(0, 3)) < 1.9)) ? 'input' : 'paste');
|
60
|
+
|
61
|
+
// the timeout is set because we can't get the value from the input without it
|
62
|
+
var pasteHandler = function(e) {
|
63
|
+
e = $.event.fix(e || window.event);
|
64
|
+
e.type = 'paste';
|
65
|
+
var el = e.target;
|
66
|
+
|
67
|
+
setTimeout(function() {
|
68
|
+
$.event.dispatch.call(el, e);
|
69
|
+
}, 1);
|
70
|
+
};
|
71
|
+
|
72
|
+
$.event.special.paste = {
|
73
|
+
setup: function() {
|
74
|
+
if (this.addEventListener) this.addEventListener(pasteEvent, pasteHandler, false);
|
75
|
+
else if (this.attachEvent) this.attachEvent('on' + pasteEvent, pasteHandler);
|
76
|
+
},
|
77
|
+
|
78
|
+
teardown: function() {
|
79
|
+
if (this.removeEventListener) this.removeEventListener(pasteEvent, pasteHandler, false);
|
80
|
+
else if (this.detachEvent) this.detachEvent('on' + pasteEvent, pasteHandler);
|
81
|
+
}
|
82
|
+
};
|
83
|
+
|
84
|
+
$.extend({
|
85
|
+
mask: {
|
86
|
+
|
87
|
+
// the mask rules. You may add yours!
|
88
|
+
// number rules will be overwritten
|
89
|
+
rules: {
|
90
|
+
'z': /[a-z]/,
|
91
|
+
'Z': /[A-Z]/,
|
92
|
+
'a': /[a-zA-Z]/,
|
93
|
+
'*': /[0-9a-zA-Z]/,
|
94
|
+
'@': /[0-9a-zA-ZçÇáàãâéèêíìóòôõúùü]/
|
95
|
+
},
|
96
|
+
|
97
|
+
// these keys will be ignored by the mask.
|
98
|
+
// all these numbers where obtained on the keydown event
|
99
|
+
keyRepresentation: {
|
100
|
+
8: 'backspace',
|
101
|
+
9: 'tab',
|
102
|
+
13: 'enter',
|
103
|
+
16: 'shift',
|
104
|
+
17: 'control',
|
105
|
+
18: 'alt',
|
106
|
+
27: 'esc',
|
107
|
+
33: 'page up',
|
108
|
+
34: 'page down',
|
109
|
+
35: 'end',
|
110
|
+
36: 'home',
|
111
|
+
37: 'left',
|
112
|
+
38: 'up',
|
113
|
+
39: 'right',
|
114
|
+
40: 'down',
|
115
|
+
45: 'insert',
|
116
|
+
46: 'delete',
|
117
|
+
116: 'f5',
|
118
|
+
123: 'f12',
|
119
|
+
224: 'command'
|
120
|
+
},
|
121
|
+
|
122
|
+
signals: {
|
123
|
+
'+': '',
|
124
|
+
'-': '-'
|
125
|
+
},
|
126
|
+
|
127
|
+
// default settings for the plugin
|
128
|
+
options: {
|
129
|
+
attr: 'alt', // an attr to look for the mask name or the mask itself
|
130
|
+
mask: null, // the mask to be used on the input
|
131
|
+
type: 'fixed', // the mask of this mask
|
132
|
+
maxLength: -1, // the maxLength of the mask
|
133
|
+
defaultValue: '', // the default value for this input
|
134
|
+
signal: false, // this should not be set, to use signal at masks put the signal you want ('-' or '+') at the default value of this mask.
|
135
|
+
// See the defined masks for a better understanding.
|
136
|
+
|
137
|
+
textAlign: true, // use false to not use text-align on any mask (at least not by the plugin, you may apply it using css)
|
138
|
+
selectCharsOnFocus: true, // select all chars from input on its focus
|
139
|
+
autoTab: true, // auto focus the next form element when you type the mask completely
|
140
|
+
setSize: false, // sets the input size based on the length of the mask (work with fixed and reverse masks only)
|
141
|
+
fixedChars: '[(),.:/ -]', // fixed chars to be used on the masks. You may change it for your needs!
|
142
|
+
|
143
|
+
onInvalid: function() {},
|
144
|
+
onValid: function() {},
|
145
|
+
onOverflow: function() {},
|
146
|
+
onFocus: function(input, evt) {},
|
147
|
+
onBlur: function(input, evt) {}
|
148
|
+
},
|
149
|
+
|
150
|
+
// masks. You may add yours!
|
151
|
+
// Ex: $.fn.setMask.masks.msk = {mask: '999'}
|
152
|
+
// and then if the 'attr' options value is 'alt', your input should look like:
|
153
|
+
// <input type="text" name="some_name" id="some_name" alt="msk" />
|
154
|
+
masks: {
|
155
|
+
'phone': {
|
156
|
+
mask: '(99) 9999-9999'
|
157
|
+
},
|
158
|
+
'phone-us': {
|
159
|
+
mask: '(999) 999-9999'
|
160
|
+
},
|
161
|
+
'cpf': {
|
162
|
+
mask: '999.999.999-99'
|
163
|
+
}, // cadastro nacional de pessoa fisica (kind of a brazillian ssn)
|
164
|
+
'cnpj': {
|
165
|
+
mask: '99.999.999/9999-99'
|
166
|
+
},
|
167
|
+
'date': {
|
168
|
+
mask: '39/19/9999'
|
169
|
+
}, // uk date
|
170
|
+
'date-us': {
|
171
|
+
mask: '19/39/9999'
|
172
|
+
},
|
173
|
+
'cep': {
|
174
|
+
mask: '99999-999'
|
175
|
+
},
|
176
|
+
'time': {
|
177
|
+
mask: '29:59'
|
178
|
+
},
|
179
|
+
'cc': {
|
180
|
+
mask: '9999 9999 9999 9999'
|
181
|
+
}, // credit card
|
182
|
+
'integer': {
|
183
|
+
mask: '999.999.999.999',
|
184
|
+
type: 'reverse'
|
185
|
+
},
|
186
|
+
'decimal': {
|
187
|
+
mask: '99,999.999.999.999',
|
188
|
+
type: 'reverse',
|
189
|
+
defaultValue: '000'
|
190
|
+
},
|
191
|
+
'decimal-us': {
|
192
|
+
mask: '99.999,999,999,999',
|
193
|
+
type: 'reverse',
|
194
|
+
defaultValue: '000'
|
195
|
+
},
|
196
|
+
'signed-decimal': {
|
197
|
+
mask: '99,999.999.999.999',
|
198
|
+
type: 'reverse',
|
199
|
+
defaultValue: '+000'
|
200
|
+
},
|
201
|
+
'signed-decimal-us': {
|
202
|
+
mask: '99,999.999.999.999',
|
203
|
+
type: 'reverse',
|
204
|
+
defaultValue: '+000'
|
205
|
+
}
|
206
|
+
},
|
207
|
+
|
208
|
+
init: function() {
|
209
|
+
// if has not inited...
|
210
|
+
if (!this.hasInit) {
|
211
|
+
|
212
|
+
var self = this,
|
213
|
+
i,
|
214
|
+
keyRep = this.keyRepresentation;
|
215
|
+
|
216
|
+
this.ignore = false;
|
217
|
+
|
218
|
+
// constructs number rules
|
219
|
+
for (i = 0; i <= 9; i++) this.rules[i] = new RegExp('[0-' + i + ']');
|
220
|
+
|
221
|
+
this.keyRep = keyRep;
|
222
|
+
// ignore keys array creation for iphone or the normal ones
|
223
|
+
this.ignoreKeys = [];
|
224
|
+
$.each(keyRep, function(key) {
|
225
|
+
self.ignoreKeys.push(parseInt(key, 10));
|
226
|
+
});
|
227
|
+
|
228
|
+
this.hasInit = true;
|
229
|
+
}
|
230
|
+
},
|
231
|
+
|
232
|
+
set: function(el, options) {
|
233
|
+
|
234
|
+
var maskObj = this,
|
235
|
+
$el = $(el),
|
236
|
+
mlStr = 'maxLength';
|
237
|
+
|
238
|
+
options = options || {};
|
239
|
+
this.init();
|
240
|
+
|
241
|
+
return $el.each(function() {
|
242
|
+
|
243
|
+
if (options.attr) maskObj.options.attr = options.attr;
|
244
|
+
|
245
|
+
var $this = $(this),
|
246
|
+
o = $.extend({}, maskObj.options),
|
247
|
+
attrValue = $this.attr(o.attr),
|
248
|
+
tmpMask = '';
|
249
|
+
|
250
|
+
// then we look for the 'attr' option
|
251
|
+
tmpMask = (typeof options == 'string') ? options : (attrValue !== '') ? attrValue : null;
|
252
|
+
if (tmpMask) o.mask = tmpMask;
|
253
|
+
|
254
|
+
// then we see if it's a defined mask
|
255
|
+
if (maskObj.masks[tmpMask]) o = $.extend(o, maskObj.masks[tmpMask]);
|
256
|
+
|
257
|
+
// then it looks if the options is an object, if it is we will overwrite the actual options
|
258
|
+
if (typeof options == 'object' && options.constructor != Array) o = $.extend(o, options);
|
259
|
+
|
260
|
+
//then we look for some metadata on the input
|
261
|
+
if ($.metadata) o = $.extend(o, $this.metadata());
|
262
|
+
|
263
|
+
if (o.mask != null) {
|
264
|
+
|
265
|
+
// prevents javascript automatic type convertion
|
266
|
+
o.mask += '';
|
267
|
+
|
268
|
+
if ($this.data('mask')) maskObj.unset($this);
|
269
|
+
|
270
|
+
var defaultValue = o.defaultValue,
|
271
|
+
reverse = (o.type === 'reverse'),
|
272
|
+
fixedCharsRegG = new RegExp(o.fixedChars, 'g');
|
273
|
+
|
274
|
+
if (o.maxLength === -1) o.maxLength = $this.attr(mlStr);
|
275
|
+
|
276
|
+
o = $.extend({}, o, {
|
277
|
+
fixedCharsReg: new RegExp(o.fixedChars),
|
278
|
+
fixedCharsRegG: fixedCharsRegG,
|
279
|
+
maskArray: o.mask.split(''),
|
280
|
+
maskNonFixedCharsArray: o.mask.replace(fixedCharsRegG, '').split('')
|
281
|
+
});
|
282
|
+
|
283
|
+
// setSize option (this is kept when the mask is removed)
|
284
|
+
if ((o.type == 'fixed' || reverse) && o.setSize && !$this.attr('size')) $this.attr('size', o.mask.length);
|
285
|
+
|
286
|
+
// sets text-align right for reverse masks
|
287
|
+
if (reverse && o.textAlign) $this.css('text-align', 'right');
|
288
|
+
|
289
|
+
if (this.value !== '' || defaultValue !== '') {
|
290
|
+
// apply mask to the current value of the input or to the default value
|
291
|
+
var val = maskObj.string((this.value !== '') ? this.value : defaultValue, o);
|
292
|
+
//setting defaultValue fixes the reset button from the form
|
293
|
+
this.defaultValue = val;
|
294
|
+
$this.val(val);
|
295
|
+
}
|
296
|
+
|
297
|
+
// compatibility patch for infinite mask, that is now repeat
|
298
|
+
if (o.type == 'infinite') o.type = 'repeat';
|
299
|
+
|
300
|
+
$this.data('mask', o);
|
301
|
+
|
302
|
+
// removes the maxLength attribute (it will be set again if you use the unset method)
|
303
|
+
$this.removeAttr(mlStr);
|
304
|
+
|
305
|
+
// setting the input events
|
306
|
+
$this.bind('keydown.mask', {
|
307
|
+
func: maskObj._onKeyDown,
|
308
|
+
thisObj: maskObj
|
309
|
+
}, maskObj._onMask)
|
310
|
+
.bind('keypress.mask', {
|
311
|
+
func: maskObj._onKeyPress,
|
312
|
+
thisObj: maskObj
|
313
|
+
}, maskObj._onMask)
|
314
|
+
.bind('keyup.mask', {
|
315
|
+
func: maskObj._onKeyUp,
|
316
|
+
thisObj: maskObj
|
317
|
+
}, maskObj._onMask)
|
318
|
+
.bind('paste.mask', {
|
319
|
+
func: maskObj._onPaste,
|
320
|
+
thisObj: maskObj
|
321
|
+
}, maskObj._onMask)
|
322
|
+
.bind('drop.mask', {
|
323
|
+
func: maskObj._onPaste,
|
324
|
+
thisObj: maskObj
|
325
|
+
}, maskObj._onMask)
|
326
|
+
.bind('focus.mask', maskObj._onFocus)
|
327
|
+
.bind('blur.mask', maskObj._onBlur)
|
328
|
+
.bind('change.mask', maskObj._onChange);
|
329
|
+
}
|
330
|
+
});
|
331
|
+
},
|
332
|
+
|
333
|
+
//unsets the mask from el
|
334
|
+
unset: function(el) {
|
335
|
+
var $el = $(el);
|
336
|
+
|
337
|
+
return $el.each(function() {
|
338
|
+
var $this = $(this);
|
339
|
+
if ($this.data('mask')) {
|
340
|
+
var maxLength = $this.data('mask').maxLength;
|
341
|
+
if (maxLength != -1) $this.attr('maxLength', maxLength);
|
342
|
+
$this.unbind('.mask')
|
343
|
+
.removeData('mask');
|
344
|
+
}
|
345
|
+
});
|
346
|
+
},
|
347
|
+
|
348
|
+
//masks a string
|
349
|
+
string: function(str, options) {
|
350
|
+
this.init();
|
351
|
+
var o = {};
|
352
|
+
if (typeof str != 'string') str = String(str);
|
353
|
+
switch (typeof options) {
|
354
|
+
case 'string':
|
355
|
+
// then we see if it's a defined mask
|
356
|
+
if (this.masks[options]) o = $.extend(o, this.masks[options]);
|
357
|
+
else o.mask = options;
|
358
|
+
break;
|
359
|
+
case 'object':
|
360
|
+
o = options;
|
361
|
+
}
|
362
|
+
if (!o.fixedChars) o.fixedChars = this.options.fixedChars;
|
363
|
+
|
364
|
+
var fixedCharsReg = new RegExp(o.fixedChars),
|
365
|
+
fixedCharsRegG = new RegExp(o.fixedChars, 'g');
|
366
|
+
|
367
|
+
// insert signal if any
|
368
|
+
if ((o.type === 'reverse') && o.defaultValue) {
|
369
|
+
if (typeof this.signals[o.defaultValue.charAt(0)] != 'undefined') {
|
370
|
+
var maybeASignal = str.charAt(0);
|
371
|
+
o.signal = (typeof this.signals[maybeASignal] != 'undefined') ? this.signals[maybeASignal] : this.signals[o.defaultValue.charAt(0)];
|
372
|
+
o.defaultValue = o.defaultValue.substring(1);
|
373
|
+
}
|
374
|
+
}
|
375
|
+
|
376
|
+
return this.__maskArray(str.split(''),
|
377
|
+
o.mask.replace(fixedCharsRegG, '').split(''),
|
378
|
+
o.mask.split(''),
|
379
|
+
o.type,
|
380
|
+
o.maxLength,
|
381
|
+
o.defaultValue,
|
382
|
+
fixedCharsReg,
|
383
|
+
o.signal);
|
384
|
+
},
|
385
|
+
|
386
|
+
// all the 3 events below are here just to fix the change event on reversed masks.
|
387
|
+
// It isn't fired in cases that the keypress event returns false (needed).
|
388
|
+
_onFocus: function(e) {
|
389
|
+
var $this = $(this),
|
390
|
+
dataObj = $this.data('mask');
|
391
|
+
dataObj.inputFocusValue = $this.val();
|
392
|
+
dataObj.changed = false;
|
393
|
+
if (dataObj.selectCharsOnFocus) $this.select();
|
394
|
+
// trigger mask function
|
395
|
+
dataObj.onFocus(this, e);
|
396
|
+
},
|
397
|
+
|
398
|
+
_onBlur: function(e) {
|
399
|
+
var $this = $(this),
|
400
|
+
dataObj = $this.data('mask');
|
401
|
+
if (dataObj.inputFocusValue != $this.val() && !dataObj.changed) $this.trigger('change');
|
402
|
+
// trigger mask function
|
403
|
+
dataObj.onBlur(this, e);
|
404
|
+
},
|
405
|
+
|
406
|
+
_onChange: function(e) {
|
407
|
+
$(this).data('mask').changed = true;
|
408
|
+
},
|
409
|
+
|
410
|
+
_onMask: function(e) {
|
411
|
+
var thisObj = e.data.thisObj,
|
412
|
+
o = {};
|
413
|
+
|
414
|
+
o._this = e.target;
|
415
|
+
o.$this = $(o._this);
|
416
|
+
o.data = o.$this.data('mask');
|
417
|
+
|
418
|
+
if (o.$this.attr('readonly') || !o.data) {
|
419
|
+
return true;
|
420
|
+
}
|
421
|
+
|
422
|
+
o[o.data.type] = true;
|
423
|
+
o.value = o.$this.val();
|
424
|
+
o.nKey = thisObj.__getKeyNumber(e);
|
425
|
+
o.range = thisObj.__getRange(o._this);
|
426
|
+
o.valueArray = o.value.split('');
|
427
|
+
return e.data.func.call(thisObj, e, o);
|
428
|
+
},
|
429
|
+
|
430
|
+
_onKeyDown: function(e, o) {
|
431
|
+
// lets say keypress at desktop == keydown at iphone (theres no keypress at iphone)
|
432
|
+
this.ignore = $.inArray(o.nKey, this.ignoreKeys) > -1 || ((e.ctrlKey || e.metaKey || e.altKey) && e.key);
|
433
|
+
if (this.ignore) {
|
434
|
+
var rep = this.keyRep[o.nKey];
|
435
|
+
o.data.onValid.call(o._this, rep || '', o.nKey);
|
436
|
+
}
|
437
|
+
return isMobile ? this._onKeyPress(e, o) : true;
|
438
|
+
},
|
439
|
+
|
440
|
+
_onKeyUp: function(e, o) {
|
441
|
+
//9=TAB_KEY 16=SHIFT_KEY
|
442
|
+
//this is a little bug, when you go to an input with tab key
|
443
|
+
//it would remove the range selected by default, and that's not a desired behavior
|
444
|
+
if (o.nKey === 9 || o.nKey === 16) return true;
|
445
|
+
|
446
|
+
if (o.repeat) {
|
447
|
+
this.__autoTab(o);
|
448
|
+
return true;
|
449
|
+
}
|
450
|
+
|
451
|
+
return this._onPaste(e, o);
|
452
|
+
},
|
453
|
+
|
454
|
+
_onPaste: function(e, o) {
|
455
|
+
// changes the signal at the data obj from the input
|
456
|
+
if (o.reverse) this.__changeSignal(e.type, o);
|
457
|
+
|
458
|
+
var $thisVal = this.__maskArray(
|
459
|
+
o.valueArray,
|
460
|
+
o.data.maskNonFixedCharsArray,
|
461
|
+
o.data.maskArray,
|
462
|
+
o.data.type,
|
463
|
+
o.data.maxLength,
|
464
|
+
o.data.defaultValue,
|
465
|
+
o.data.fixedCharsReg,
|
466
|
+
o.data.signal);
|
467
|
+
|
468
|
+
o.$this.val($thisVal);
|
469
|
+
// this makes the caret stay at first position when
|
470
|
+
// the user removes all values in an input and the plugin adds the default value to it (if it haves one).
|
471
|
+
if (!o.reverse && o.data.defaultValue.length && (o.range.start === o.range.end)) this.__setRange(o._this, o.range.start, o.range.end);
|
472
|
+
|
473
|
+
//fix so ie's and safari's caret won't go to the end of the input value.
|
474
|
+
if (($.browser.msie || $.browser.safari) && !o.reverse) this.__setRange(o._this, o.range.start, o.range.end);
|
475
|
+
|
476
|
+
if (this.ignore) return true;
|
477
|
+
|
478
|
+
this.__autoTab(o);
|
479
|
+
return true;
|
480
|
+
},
|
481
|
+
|
482
|
+
_onKeyPress: function(e, o) {
|
483
|
+
|
484
|
+
if (this.ignore) return true;
|
485
|
+
|
486
|
+
// changes the signal at the data obj from the input
|
487
|
+
if (o.reverse) this.__changeSignal(e.type, o);
|
488
|
+
|
489
|
+
var c = String.fromCharCode(o.nKey),
|
490
|
+
rangeStart = o.range.start,
|
491
|
+
rawValue = o.value,
|
492
|
+
maskArray = o.data.maskArray;
|
493
|
+
|
494
|
+
if (o.reverse) {
|
495
|
+
// the input value from the range start to the value start
|
496
|
+
var valueStart = rawValue.substr(0, rangeStart),
|
497
|
+
// the input value from the range end to the value end
|
498
|
+
valueEnd = rawValue.substr(o.range.end, rawValue.length);
|
499
|
+
|
500
|
+
rawValue = valueStart + c + valueEnd;
|
501
|
+
//necessary, if not decremented you will be able to input just the mask.length-1 if signal!=''
|
502
|
+
//ex: mask:99,999.999.999 you will be able to input 99,999.999.99
|
503
|
+
if (o.data.signal && (rangeStart - o.data.signal.length > 0)) {
|
504
|
+
rangeStart -= o.data.signal.length;
|
505
|
+
}
|
506
|
+
}
|
507
|
+
|
508
|
+
var valueArray = rawValue.replace(o.data.fixedCharsRegG, '').split(''),
|
509
|
+
// searches for fixed chars begining from the range start position, till it finds a non fixed
|
510
|
+
extraPos = this.__extraPositionsTill(rangeStart, maskArray, o.data.fixedCharsReg);
|
511
|
+
|
512
|
+
o.rsEp = rangeStart + extraPos;
|
513
|
+
|
514
|
+
if (o.repeat) {
|
515
|
+
o.rsEp = 0;
|
516
|
+
}
|
517
|
+
|
518
|
+
// if the rule for this character doesnt exist (value.length is bigger than mask.length)
|
519
|
+
// added a verification for maxLength in the case of the repeat type mask
|
520
|
+
if (!this.rules[maskArray[o.rsEp]] || (o.data.maxLength != -1 && valueArray.length >= o.data.maxLength && o.repeat)) {
|
521
|
+
// auto focus on the next input of the current form
|
522
|
+
o.data.onOverflow.call(o._this, c, o.nKey);
|
523
|
+
return false;
|
524
|
+
}
|
525
|
+
|
526
|
+
// if the new character is not obeying the law...
|
527
|
+
else if (!this.rules[maskArray[o.rsEp]].test(c)) {
|
528
|
+
o.data.onInvalid.call(o._this, c, o.nKey);
|
529
|
+
return false;
|
530
|
+
} else {
|
531
|
+
o.data.onValid.call(o._this, c, o.nKey);
|
532
|
+
}
|
533
|
+
|
534
|
+
var $thisVal = this.__maskArray(
|
535
|
+
valueArray,
|
536
|
+
o.data.maskNonFixedCharsArray,
|
537
|
+
maskArray,
|
538
|
+
o.data.type,
|
539
|
+
o.data.maxLength,
|
540
|
+
o.data.defaultValue,
|
541
|
+
o.data.fixedCharsReg,
|
542
|
+
o.data.signal,
|
543
|
+
extraPos);
|
544
|
+
|
545
|
+
if (!o.repeat) {
|
546
|
+
o.$this.val($thisVal);
|
547
|
+
}
|
548
|
+
|
549
|
+
return (o.reverse) ? this._keyPressReverse(e, o) : (o.fixed) ? this._keyPressFixed(e, o) : true;
|
550
|
+
},
|
551
|
+
|
552
|
+
_keyPressFixed: function(e, o) {
|
553
|
+
|
554
|
+
if (o.range.start == o.range.end) {
|
555
|
+
// the 0 thing is because theres an unwanted behavior when you put a default
|
556
|
+
// value on a fixed mask and you select the value from the input the range would go to the
|
557
|
+
// end of the string when you enter a char. with this it will overwrite the first char wich is a better behavior.
|
558
|
+
// opera fix, cant have range value bigger than value length, i think it loops thought the input value...
|
559
|
+
if ((o.rsEp === 0 && o.value.length === 0) || o.rsEp < o.value.length) this.__setRange(o._this, o.rsEp, o.rsEp + 1);
|
560
|
+
} else this.__setRange(o._this, o.range.start, o.range.end);
|
561
|
+
|
562
|
+
return true;
|
563
|
+
},
|
564
|
+
|
565
|
+
_keyPressReverse: function(e, o) {
|
566
|
+
// fix for ie
|
567
|
+
// this bug was pointed by Pedro Martins
|
568
|
+
// it fixes a strange behavior that ie was having after a char was inputted in a text input that
|
569
|
+
// had its content selected by any range
|
570
|
+
if ($.browser.msie && ((o.range.start === 0 && o.range.end === 0) || o.range.start != o.range.end)) this.__setRange(o._this, o.value.length);
|
571
|
+
return false;
|
572
|
+
},
|
573
|
+
|
574
|
+
__autoTab: function(o) {
|
575
|
+
if (o.data.autoTab && (
|
576
|
+
(
|
577
|
+
o.$this.val().length >= o.data.maskArray.length && !o.repeat) || (
|
578
|
+
o.data.maxLength != -1 && o.valueArray.length >= o.data.maxLength && o.repeat))) {
|
579
|
+
var nextEl = this.__getNextInput(o._this, o.data.autoTab);
|
580
|
+
if (nextEl) {
|
581
|
+
o.$this.trigger('blur');
|
582
|
+
nextEl.focus().select();
|
583
|
+
}
|
584
|
+
}
|
585
|
+
},
|
586
|
+
|
587
|
+
// changes the signal at the data obj from the input
|
588
|
+
__changeSignal: function(eventType, o) {
|
589
|
+
if (o.data.signal !== false) {
|
590
|
+
var inputChar = (eventType === 'paste') ? o.value.charAt(0) : String.fromCharCode(o.nKey);
|
591
|
+
if (this.signals && (typeof this.signals[inputChar] !== 'undefined')) {
|
592
|
+
o.data.signal = this.signals[inputChar];
|
593
|
+
}
|
594
|
+
}
|
595
|
+
},
|
596
|
+
|
597
|
+
__getKeyNumber: function(e) {
|
598
|
+
return (e.charCode || e.keyCode || e.which);
|
599
|
+
},
|
600
|
+
|
601
|
+
// this function is totaly specific to be used with this plugin, youll never need it
|
602
|
+
// it gets the array representing an unmasked string and masks it depending on the type of the mask
|
603
|
+
__maskArray: function(valueArray, maskNonFixedCharsArray, maskArray, type, maxlength, defaultValue, fixedCharsReg, signal, extraPos) {
|
604
|
+
if (type === 'reverse') valueArray.reverse();
|
605
|
+
valueArray = this.__removeInvalidChars(valueArray, maskNonFixedCharsArray, type === 'repeat' || type === 'infinite');
|
606
|
+
if (defaultValue) valueArray = this.__applyDefaultValue.call(valueArray, defaultValue);
|
607
|
+
valueArray = this.__applyMask(valueArray, maskArray, extraPos, fixedCharsReg);
|
608
|
+
switch (type) {
|
609
|
+
case 'reverse':
|
610
|
+
valueArray.reverse();
|
611
|
+
return (signal || '') + valueArray.join('').substring(valueArray.length - maskArray.length);
|
612
|
+
case 'infinite':
|
613
|
+
case 'repeat':
|
614
|
+
var joinedValue = valueArray.join('');
|
615
|
+
return (maxlength !== -1 && valueArray.length >= maxlength) ? joinedValue.substring(0, maxlength) : joinedValue;
|
616
|
+
default:
|
617
|
+
return valueArray.join('').substring(0, maskArray.length);
|
618
|
+
}
|
619
|
+
return '';
|
620
|
+
},
|
621
|
+
|
622
|
+
// applyes the default value to the result string
|
623
|
+
__applyDefaultValue: function(defaultValue) {
|
624
|
+
var defLen = defaultValue.length,
|
625
|
+
thisLen = this.length,
|
626
|
+
i;
|
627
|
+
//removes the leading chars
|
628
|
+
for (i = thisLen - 1; i >= 0; i--) {
|
629
|
+
if (this[i] == defaultValue.charAt(0)) {
|
630
|
+
this.pop();
|
631
|
+
} else break;
|
632
|
+
}
|
633
|
+
// apply the default value
|
634
|
+
for (i = 0; i < defLen; i++) if (!this[i]) {
|
635
|
+
this[i] = defaultValue.charAt(i);
|
636
|
+
}
|
637
|
+
|
638
|
+
return this;
|
639
|
+
},
|
640
|
+
|
641
|
+
// Removes values that doesnt match the mask from the valueArray
|
642
|
+
// Returns the array without the invalid chars.
|
643
|
+
__removeInvalidChars: function(valueArray, maskNonFixedCharsArray, repeatType) {
|
644
|
+
// removes invalid chars
|
645
|
+
for (var i = 0, y = 0; i < valueArray.length; i++) {
|
646
|
+
if (maskNonFixedCharsArray[y] && this.rules[maskNonFixedCharsArray[y]] && !this.rules[maskNonFixedCharsArray[y]].test(valueArray[i])) {
|
647
|
+
valueArray.splice(i, 1);
|
648
|
+
if (!repeatType) y--;
|
649
|
+
i--;
|
650
|
+
}
|
651
|
+
if (!repeatType) y++;
|
652
|
+
}
|
653
|
+
return valueArray;
|
654
|
+
},
|
655
|
+
|
656
|
+
// Apply the current input mask to the valueArray and returns it.
|
657
|
+
__applyMask: function(valueArray, maskArray, plus, fixedCharsReg) {
|
658
|
+
if (typeof plus == 'undefined') plus = 0;
|
659
|
+
// apply the current mask to the array of chars
|
660
|
+
for (var i = 0; i < valueArray.length + plus; i++) {
|
661
|
+
if (maskArray[i] && fixedCharsReg.test(maskArray[i])) valueArray.splice(i, 0, maskArray[i]);
|
662
|
+
}
|
663
|
+
return valueArray;
|
664
|
+
},
|
665
|
+
|
666
|
+
// searches for fixed chars begining from the range start position, till it finds a non fixed
|
667
|
+
__extraPositionsTill: function(rangeStart, maskArray, fixedCharsReg) {
|
668
|
+
var extraPos = 0;
|
669
|
+
while (fixedCharsReg.test(maskArray[rangeStart++])) {
|
670
|
+
extraPos++;
|
671
|
+
}
|
672
|
+
return extraPos;
|
673
|
+
},
|
674
|
+
|
675
|
+
__getNextInput: function(input, selector) {
|
676
|
+
var form = input.form;
|
677
|
+
|
678
|
+
if (form == null) {
|
679
|
+
return null;
|
680
|
+
}
|
681
|
+
|
682
|
+
var formEls = form.elements,
|
683
|
+
initialInputIndex = $.inArray(input, formEls) + 1,
|
684
|
+
len = formEls.length,
|
685
|
+
$input = null,
|
686
|
+
i;
|
687
|
+
|
688
|
+
// look for next input on the form of the pased input
|
689
|
+
for (i = initialInputIndex; i < len; i++) {
|
690
|
+
$input = $(formEls[i]);
|
691
|
+
if (this.__isNextInput($input, selector)) {
|
692
|
+
return $input;
|
693
|
+
}
|
694
|
+
}
|
695
|
+
|
696
|
+
var forms = document.forms,
|
697
|
+
initialFormIndex = $.inArray(input.form, forms) + 1,
|
698
|
+
y, tmpFormEls, _len = forms.length;
|
699
|
+
// look for the next forms for the next input
|
700
|
+
for (y = initialFormIndex; y < _len; y++) {
|
701
|
+
tmpFormEls = forms[y].elements;
|
702
|
+
len = tmpFormEls.length;
|
703
|
+
for (i = 0; i < len; i++) {
|
704
|
+
$input = $(tmpFormEls[i]);
|
705
|
+
if (this.__isNextInput($input, selector)) {
|
706
|
+
return $input;
|
707
|
+
}
|
708
|
+
}
|
709
|
+
}
|
710
|
+
return null;
|
711
|
+
},
|
712
|
+
|
713
|
+
__isNextInput: function($formEl, selector) {
|
714
|
+
var formEl = $formEl.get(0);
|
715
|
+
return formEl && (formEl.offsetWidth > 0 || formEl.offsetHeight > 0) && formEl.nodeName != 'FIELDSET' && (selector === true || (typeof selector == 'string' && $formEl.is(selector)));
|
716
|
+
},
|
717
|
+
|
718
|
+
// http://www.bazon.net/mishoo/articles.epl?art_id=1292
|
719
|
+
__setRange: function(input, start, end) {
|
720
|
+
if (typeof end == 'undefined') {
|
721
|
+
end = start;
|
722
|
+
}
|
723
|
+
if (input.setSelectionRange) {
|
724
|
+
input.setSelectionRange(start, end);
|
725
|
+
} else {
|
726
|
+
// assumed IE
|
727
|
+
var range = input.createTextRange();
|
728
|
+
range.collapse();
|
729
|
+
range.moveStart('character', start);
|
730
|
+
range.moveEnd('character', end - start);
|
731
|
+
range.select();
|
732
|
+
}
|
733
|
+
},
|
734
|
+
|
735
|
+
// adaptation from http://digitarald.de/project/autocompleter/
|
736
|
+
__getRange: function(input) {
|
737
|
+
if (!$.browser.msie && !$.browser.android) return {
|
738
|
+
start: input.selectionStart,
|
739
|
+
end: input.selectionEnd
|
740
|
+
};
|
741
|
+
var pos = {
|
742
|
+
start: 0,
|
743
|
+
end: 0
|
744
|
+
},
|
745
|
+
range = document.selection.createRange();
|
746
|
+
pos.start = 0 - range.duplicate().moveStart('character', - 100000);
|
747
|
+
pos.end = pos.start + range.text.length;
|
748
|
+
return pos;
|
749
|
+
},
|
750
|
+
|
751
|
+
//deprecated
|
752
|
+
unmaskedVal: function(el) {
|
753
|
+
return $(el).val().replace($.mask.fixedCharsRegG, '');
|
754
|
+
}
|
755
|
+
|
756
|
+
}
|
757
|
+
});
|
758
|
+
|
759
|
+
$.fn.extend({
|
760
|
+
setMask: function(options) {
|
761
|
+
return $.mask.set(this, options);
|
762
|
+
},
|
763
|
+
unsetMask: function() {
|
764
|
+
return $.mask.unset(this);
|
765
|
+
},
|
766
|
+
//deprecated
|
767
|
+
unmaskedVal: function() {
|
768
|
+
return $.mask.unmaskedVal(this[0]);
|
769
|
+
}
|
770
|
+
});
|
771
|
+
})(jQuery);
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meiomask-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.12
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Fabio M. Costa
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-11-27 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: jquery.meiomask for rails.
|
15
|
+
email:
|
16
|
+
- fabiomcosta@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- AUTHORS.md
|
23
|
+
- CONTRIBUTING.md
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE-MIT.md
|
26
|
+
- README.md
|
27
|
+
- Rakefile
|
28
|
+
- lib/meiomask-rails.rb
|
29
|
+
- meiomask-rails.gemspec
|
30
|
+
- vendor/assets/javascripts/meiomask.js
|
31
|
+
homepage: https://github.com/fabiomcosta/jquery-meiomask
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
requirements: []
|
50
|
+
rubyforge_project:
|
51
|
+
rubygems_version: 1.8.25
|
52
|
+
signing_key:
|
53
|
+
specification_version: 3
|
54
|
+
summary: jquery.meiomask for rails.
|
55
|
+
test_files: []
|
56
|
+
has_rdoc:
|