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 ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/AUTHORS.md ADDED
@@ -0,0 +1 @@
1
+ Fábio M. Costa (http://github.com/fabiomcosta)
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,2 @@
1
+ ## Contributing
2
+ Some details on how to contribute and stuff for maintainers of the project.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in meiomask-rails.gemspec
4
+ gemspec
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,6 @@
1
+ module MeioMask
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -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: