meiomask-rails 1.1.12

Sign up to get free protection for your applications and to get access to all the features.
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: