diff --git a/ch.js b/ch.js
new file mode 100644
index 00000000..cc1245c1
--- /dev/null
+++ b/ch.js
@@ -0,0 +1,3 @@
+'use strict';
+
+module.exports = require('./src/angular-input-masks.ch');
diff --git a/ch.test.js b/ch.test.js
new file mode 100644
index 00000000..4acae8fb
--- /dev/null
+++ b/ch.test.js
@@ -0,0 +1,11 @@
+'use strict';
+
+describe('angular-input-masks-standalone', function() {
+ var moduleName = require('./ch.js');
+
+ beforeEach(angular.mock.module('ui.utils.masks'));
+
+ it('should export the module name', function() {
+ expect(moduleName).toBe('ui.utils.masks');
+ });
+});
diff --git a/gulpfile.js b/gulpfile.js
index f739f72c..b48fa05f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -63,6 +63,10 @@ gulp.task('build', ['build-dependencies'], function() {
fileName: 'angular-input-masks.us.js',
debug: false,
bundleExternal: false
+ }, {
+ fileName: 'angular-input-masks.ch.js',
+ debug: false,
+ bundleExternal: false
}, {
fileName: 'angular-input-masks.js',
outputFileName: 'angular-input-masks-standalone.js',
diff --git a/src/angular-input-masks.ch.js b/src/angular-input-masks.ch.js
new file mode 100644
index 00000000..acd7ddbe
--- /dev/null
+++ b/src/angular-input-masks.ch.js
@@ -0,0 +1,6 @@
+'use strict';
+
+module.exports = angular.module('ui.utils.masks', [
+ require('./global/global-masks'),
+ require('./ch/ch-masks')
+]).name;
diff --git a/src/angular-input-masks.js b/src/angular-input-masks.js
index 9d2a31f2..293518a7 100644
--- a/src/angular-input-masks.js
+++ b/src/angular-input-masks.js
@@ -3,5 +3,6 @@
module.exports = angular.module('ui.utils.masks', [
require('./global/global-masks'),
require('./br/br-masks'),
- require('./us/us-masks')
+ require('./us/us-masks'),
+ require('./ch/ch-masks')
]).name;
diff --git a/src/ch/ch-masks.js b/src/ch/ch-masks.js
new file mode 100644
index 00000000..14215bdb
--- /dev/null
+++ b/src/ch/ch-masks.js
@@ -0,0 +1,8 @@
+'use strict';
+
+var m = angular.module('ui.utils.masks.ch', [
+ require('../helpers'),
+])
+.directive('uiChPhoneNumber', require('./phone/ch-phone'));
+
+module.exports = m.name;
diff --git a/src/ch/phone/ch-phone.html b/src/ch/phone/ch-phone.html
new file mode 100644
index 00000000..8bfbc67d
--- /dev/null
+++ b/src/ch/phone/ch-phone.html
@@ -0,0 +1,29 @@
+
+
+
+
+ CH Phone Number Spec
+
+
+
+
+
+
+
+
+
diff --git a/src/ch/phone/ch-phone.js b/src/ch/phone/ch-phone.js
new file mode 100644
index 00000000..bf75a2f8
--- /dev/null
+++ b/src/ch/phone/ch-phone.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var StringMask = require('string-mask');
+var maskFactory = require('mask-factory');
+
+var phoneMask = new StringMask('+00 00 000 00 00');
+
+module.exports = maskFactory({
+ clearValue: function(rawValue) {
+ return rawValue.toString().replace(/[^0-9]/g, '').slice(0, 11);
+ },
+ format: function(cleanValue) {
+ var formatedValue;
+
+ formatedValue = phoneMask.apply(cleanValue) || '';
+
+ return formatedValue.trim().replace(/[^0-9]$/, '');
+ },
+ validations: {
+ chPhoneNumber: function(value) {
+ var valueLength = value && value.toString().length;
+ return valueLength === 11;
+ }
+ }
+});
diff --git a/src/ch/phone/ch-phone.spec.js b/src/ch/phone/ch-phone.spec.js
new file mode 100644
index 00000000..34406827
--- /dev/null
+++ b/src/ch/phone/ch-phone.spec.js
@@ -0,0 +1,88 @@
+'use strict';
+
+describe('ui.utils.masks.number', function() {
+ it('should load the demo page', function() {
+ browser.get('/src/ch/phone/ch-phone.html');
+ expect(browser.getTitle()).toEqual('CH Phone Number Spec');
+ });
+
+ describe('ui-ch-phone-number:', function() {
+ it('should apply a phone number mask while the user is typping:', function() {
+ var BS = protractor.Key.BACK_SPACE;
+
+ var tests = [
+ {key:'1', viewValue:'+1', modelValue:'1'},
+ {key:'2', viewValue:'+12', modelValue:'12'},
+ {key:'3', viewValue:'+12 3', modelValue:'123'},
+ {key:'4', viewValue:'+12 34', modelValue:'1234'},
+ {key:'5', viewValue:'+12 34 5', modelValue:'12345'},
+ {key:'6', viewValue:'+12 34 56', modelValue:'123456'},
+ {key:'7', viewValue:'+12 34 567', modelValue:'1234567'},
+ {key:'8', viewValue:'+12 34 567 8', modelValue:'12345678'},
+ {key:'9', viewValue:'+12 34 567 89', modelValue:'123456789'},
+ {key:'0', viewValue:'+12 34 567 89 0', modelValue:'1234567890'},
+ {key:'1', viewValue:'+12 34 567 89 01', modelValue:'12345678901'},
+ {key:'2', viewValue:'+12 34 567 89 01', modelValue:'12345678901'},
+ {key:BS, viewValue:'+12 34 567 89 0', modelValue:'1234567890'},
+ {key:BS, viewValue:'+12 34 567 89 ', modelValue:'123456789'},
+ {key:BS, viewValue:'+12 34 567 89', modelValue:'123456789'},
+ {key:BS, viewValue:'+12 34 567 8', modelValue:'12345678'},
+ {key:BS, viewValue:'+12 34 567 ', modelValue:'1234567'},
+ {key:BS, viewValue:'+12 34 567', modelValue:'1234567'},
+ {key:BS, viewValue:'+12 34 56', modelValue:'123456'},
+ {key:BS, viewValue:'+12 34 5', modelValue:'12345'},
+ {key:BS, viewValue:'+12 34 ', modelValue:'1234'},
+ {key:BS, viewValue:'+12 34', modelValue:'1234'},
+ {key:BS, viewValue:'+12 3', modelValue:'123'},
+ {key:BS, viewValue:'+12 ', modelValue:'12'},
+ {key:BS, viewValue:'+12', modelValue:'12'},
+ {key:BS, viewValue:'+1', modelValue:'1'},
+ {key:BS, viewValue:'', modelValue:''},
+ ];
+
+ var input = element(by.model('phoneNumber')),
+ value = element(by.exactBinding('phoneNumber'));
+
+ for (var i = 0; i < tests.length; i++) {
+ input.sendKeys(tests[i].key);
+ expect(input.getAttribute('value')).toEqual(tests[i].viewValue);
+ expect(value.getText()).toEqual(tests[i].modelValue);
+ }
+ });
+
+ it('should apply a phone number mask in a model with default value:', function() {
+ var BS = protractor.Key.BACK_SPACE;
+
+ var tests = [
+ {key:'1', viewValue:'+1', modelValue:'1'},
+ {key:'2', viewValue:'+12', modelValue:'12'},
+ {key:'3', viewValue:'+12 3', modelValue:'123'},
+ {key:'4', viewValue:'+12 34', modelValue:'1234'},
+ {key:'5', viewValue:'+12 34 5', modelValue:'12345'},
+ {key:'6', viewValue:'+12 34 56', modelValue:'123456'},
+ {key:'7', viewValue:'+12 34 567', modelValue:'1234567'},
+ {key:BS, viewValue:'+12 34 56', modelValue:'123456'},
+ {key:BS, viewValue:'+12 34 5', modelValue:'12345'},
+ {key:BS, viewValue:'+12 34 ', modelValue:'1234'},
+ {key:BS, viewValue:'+12 34', modelValue:'1234'},
+ {key:BS, viewValue:'+12 3', modelValue:'123'},
+ {key:BS, viewValue:'+12 ', modelValue:'12'},
+ {key:BS, viewValue:'+12', modelValue:'12'},
+ {key:BS, viewValue:'+1', modelValue:'1'},
+ {key:BS, viewValue:'', modelValue:''},
+ ];
+
+ var input = element(by.model('initializedPhoneNumber')),
+ value = element(by.exactBinding('initializedPhoneNumber'));
+
+ expect(input.getAttribute('value')).toEqual('+41 79 000 00 00');
+ input.clear();
+
+ for (var i = 0; i < tests.length; i++) {
+ input.sendKeys(tests[i].key);
+ expect(input.getAttribute('value')).toEqual(tests[i].viewValue);
+ expect(value.getText()).toEqual(tests[i].modelValue);
+ }
+ });
+ });
+});
diff --git a/src/ch/phone/ch-phone.test.js b/src/ch/phone/ch-phone.test.js
new file mode 100644
index 00000000..2679734a
--- /dev/null
+++ b/src/ch/phone/ch-phone.test.js
@@ -0,0 +1,78 @@
+'use strict';
+
+require('../ch-masks');
+
+describe('ui-ch-phone-number', function() {
+ beforeEach(angular.mock.module('ui.utils.masks.ch'));
+
+ it('should throw an error if used without ng-model', function() {
+ expect(function() {
+ TestUtil.compile('');
+ }).toThrow();
+ });
+
+ it('should register a $parser and a $formatter', function() {
+ var input = TestUtil.compile('');
+ var model = input.controller('ngModel');
+
+ var maskedInput = TestUtil.compile('');
+ var maskedModel = maskedInput.controller('ngModel');
+
+ expect(maskedModel.$parsers.length).toBe(model.$parsers.length + 1);
+ expect(maskedModel.$formatters.length).toBe(model.$formatters.length + 1);
+ });
+
+ it('should format initial model values', function() {
+ var input = TestUtil.compile('', {
+ model: '41790000000'
+ });
+
+ var model = input.controller('ngModel');
+ expect(model.$viewValue).toBe('+41 79 000 00 00');
+ });
+
+ it('should ignore non digits', function() {
+ var input = TestUtil.compile('');
+ var model = input.controller('ngModel');
+
+ var tests = [
+ {value:'@', viewValue:'', modelValue:''},
+ {value:'2-', viewValue:'+2', modelValue:'2'},
+ {value:'23a', viewValue:'+23', modelValue:'23'},
+ {value:'23_34', viewValue:'+23 34', modelValue:'2334'},
+ {value:'23346!', viewValue:'+23 34 6', modelValue:'23346'},
+ {value:'23346!324', viewValue:'+23 34 632 4', modelValue:'23346324'},
+ ];
+
+ tests.forEach(function(test) {
+ input.val(test.value).triggerHandler('input');
+ expect(model.$viewValue).toBe(test.viewValue);
+ expect(model.$modelValue).toBe(test.modelValue);
+ });
+ });
+
+ it('should validate a phone number', function() {
+ var input = TestUtil.compile('', {
+ model: '417900'
+ });
+
+ var model = input.controller('ngModel');
+ expect(model.$error.chPhoneNumber).toBe(true);
+ input.val('41790000000').triggerHandler('input');
+ expect(model.$error.chPhoneNumber).toBeUndefined();
+ });
+
+ it('should use the type of the model value (if initialized)', function() {
+ var input = TestUtil.compile('', {
+ model: '41790000000'
+ });
+
+ var model = input.controller('ngModel');
+ expect(model.$viewValue).toBe('+41 79 000 00 00');
+ expect(model.$modelValue).toBe('41790000000');
+ input.val('41619618686').triggerHandler('input');
+ expect(model.$viewValue).toBe('+41 61 961 86 86');
+ expect(model.$modelValue).toBe('41619618686');
+ });
+});