Created
July 15, 2016 22:40
-
-
Save megamaddu/303ff39c10af8a5933e56279794453a6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module = angular.module 'inputHelpers', [] | |
if not Bacon? | |
console.log 'window.Bacon not found, skipping input validator initialization' | |
return | |
module.constant 'bacon', Bacon | |
_masks = | |
ssn: 'ddd-dd-dddd' | |
ien: 'dd-ddddddd' #ien: 'dd-ddddddd,d-ddddddd' | |
phone: '(ddd) ddd-dddd' | |
zip: 'ddddd' #zip: 'ddddd,ddddd-dddd' | |
module.directive 'input', ['bacon', (Bacon) -> | |
restrict: 'E' | |
require: '?ngModel' | |
link: (scope, element, attr, ctrl) -> | |
masks = (attr.masks or _masks[attr.type])?.split ',' | |
return if not ctrl or not masks or not masks.length | |
getVal = -> element.val() | |
setVal = (val) -> element.val val | |
getPos = getCursorPositionBinder element | |
setPos = setCursorPositionBinder element | |
[lastMask] = masks | |
if getPos? and setPos? | |
_keyups = element.asEventStream 'keypress' | |
.filter isNonMetaCharKeyEvent | |
.map (e) -> | |
e.preventDefault() | |
value = getVal() | |
key: getKey e | |
value: value | |
originalValue: value | |
position: getPos() | |
done: false | |
.map (e) -> | |
masks.map (mask) -> handlForMask e, mask | |
.map (results) -> | |
result = results.reduce (best, result) -> | |
if not best? | |
result | |
else if result.suggestion.value and result.mask is lastMask | |
result | |
else if result.suggestion.rating > best.suggestion.rating | |
result | |
else | |
best | |
lastMask = result.mask | |
result | |
.onValue (result) -> | |
{event, suggestion} = result | |
if suggestion.value? and suggestion.position? | |
setVal suggestion.value | |
setPos suggestion.position | |
ctrl.$setViewValue suggestion.value | |
] | |
anyMaskMatch = (masks, value) -> | |
masks.some (mask) -> | |
value? and value.length == mask.length and | |
isPartialMatchForMask mask, value | |
isPartialMatchForMask = (mask, value) -> | |
chars = value.split '' | |
chars.every (char, i) -> | |
m = mask[i] | |
valueCharIsValid char, m | |
getKey = (e) -> | |
if e.charCode? then e.charCode else e.keyCode | |
isNonMetaCharKeyEvent = (e) -> | |
not e.metaKey and not e.ctrlKey and | |
isCharKey getKey e | |
isCharKey = (k) -> | |
k >= 32 and k <= 126 | |
isNumericKey = (k) -> | |
k >= 47 and k <= 57 | |
isNonNumericKey = (k) -> | |
isCharKey k and not isNumericKey k | |
handlForMask = (e, mask) -> | |
e = hash e, mask: mask | |
m = mask[e.position] | |
suggestion = switch | |
when not m then suggestCancel e | |
when m == 'd' then handleNumeric e | |
when m == 'w' then handleNonNumeric e | |
when m == '_' then handleWild e | |
else checkConstantsAndRecurse e | |
event: e | |
suggestion: suggestion | |
done = (e) -> | |
rating: 1 | |
value: e.value | |
position: e.position | |
suggestCancel = (e) -> | |
rating: 0 | |
value: null | |
position: null | |
handleNumeric = (e) -> | |
if not isNumericKey e.key | |
suggestCancel e | |
else | |
checkConstantsAndInsert e | |
handleNonNumeric = (e) -> | |
if not isNonNumericKey e.key | |
suggestCancel e | |
else | |
checkConstantsAndInsert e | |
handleWild = (e) -> | |
if not isNumericKey e.key and not isNonNumericKey e.key | |
suggestCancel e | |
else | |
checkConstantsAndInsert e | |
checkConstantsAndInsert = (e) -> | |
e = insertOrOverwrite e | |
e = cleanConstants e | |
rating: 10 - Math.abs(e.value.length - e.originalValue.length) | |
value: e.value | |
position: e.position | |
checkConstantsAndRecurse = (e) -> | |
e = cleanConstants e | |
if e.done | |
done e | |
else | |
handlForMask e, e.mask | |
.suggestion | |
cleanConstants = (e) -> | |
val = e.value | |
for m, i in e.mask.split '' when i < val.length or i is e.position | |
do (m, i) -> | |
return if e.done | |
isConst = m isnt 'd' and m isnt 'w' and m isnt '_' | |
e = cleanPos m, isConst, i, e | |
e | |
cleanPos = (m, isConst, i, e) -> | |
{value, position} = e | |
c = value[i] | |
if isConst | |
if position < i and c isnt m or position == i | |
position += 1 | |
if c isnt m | |
value = splice value, i, 0, m | |
else if c? and not valueCharIsValid c, m | |
position -= i < position ? 1 : 0 | |
value = splice value, i, 1 | |
hash e, | |
value: value | |
position: position | |
done: m is value[i] is String.fromCharCode e.key | |
splice = (s, i, n, c) -> | |
s = s.split '' | |
s.splice i, n, c | |
s.join '' | |
valueCharIsValid = (v, m) -> | |
k = v.charCodeAt 0 | |
switch | |
when not m then false | |
when m == 'd' then isNumericKey k | |
when m == 'w' then isNonNumericKey k | |
when m == '_' then isNumericKey k or isNonNumericKey k | |
else m == char | |
insertOrOverwrite = (e) -> | |
{value, position, mask} = e | |
overwrite = value? and mask? and value.length >= mask.length | |
value = splice value, position, overwrite ? 1 : 0, String.fromCharCode e.key | |
hash e, | |
value: value | |
position: position + 1 | |
hash = (e, v) -> | |
key: if v.key? then v.key else e.key | |
value: if v.value? then v.value else e.value | |
originalValue: if v.originalValue? then v.originalValue else e.originalValue | |
position: if v.position? then v.position else e.position | |
mask: if v.mask? then v.mask else e.mask | |
done: if v.done? then v.done else e.done | |
getCursorPositionBinder = (element) -> | |
el = element.get 0 | |
if el?.selectionStart? | |
() -> | |
el.selectionStart | |
else if document.selection?.createRange? | |
() -> | |
el.focus() | |
Sel = document.selection.createRange() | |
SelLength = document.selection.createRange().text.length | |
Sel.moveStart 'character', -el.value.length | |
pos = Sel.text.length - SelLength | |
pos | |
else null | |
setCursorPositionBinder = (element) -> | |
el = element.get 0 | |
if el.setSelectionRange? | |
(pos) -> | |
el.setSelectionRange pos, pos | |
else if el.createTextRange? | |
(pos) -> | |
range = el.createTextRange() | |
range.collapse true | |
range.moveEnd 'character', pos | |
range.moveStart 'character', pos | |
range.select() | |
else null |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment