From 6c1b45087c2757be8832acc7a86ff0c9c3816a45 Mon Sep 17 00:00:00 2001 From: Charles Dupoiron Date: Tue, 17 Mar 2015 17:44:12 +0100 Subject: [PATCH] feat(uiFrPhoneMask): implement french phone number format --- README.md | 3 ++ demo/fr.html | 27 +++++++++++++++ fr.js | 1 + fr.test.js | 9 +++++ gulpfile.js | 8 +++-- package.json | 2 ++ src/angular-input-masks.fr.js | 4 +++ src/angular-input-masks.js | 5 +-- src/fr/fr-masks.js | 8 +++++ src/fr/phone/fr-phone.html | 29 ++++++++++++++++ src/fr/phone/fr-phone.js | 25 ++++++++++++++ src/fr/phone/fr-phone.spec.js | 64 +++++++++++++++++++++++++++++++++++ src/fr/phone/fr-phone.test.js | 53 +++++++++++++++++++++++++++++ 13 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 demo/fr.html create mode 100644 fr.js create mode 100644 fr.test.js create mode 100644 src/angular-input-masks.fr.js create mode 100644 src/fr/fr-masks.js create mode 100644 src/fr/phone/fr-phone.html create mode 100644 src/fr/phone/fr-phone.js create mode 100644 src/fr/phone/fr-phone.spec.js create mode 100644 src/fr/phone/fr-phone.test.js diff --git a/README.md b/README.md index 8051132b..3f0c1cc5 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,7 @@ _See more usage examples in the [Demo page](http://assisrafael.github.io/angular - ui-br-car-plate-mask - ui-scientific-notation-mask - ui-us-phone-number +- ui-fr-phone-number ## Other build options @@ -221,6 +222,7 @@ If you are using npm (without browserify): - angular-input-masks-dependencies.js: provides all external dependencies (string-mask, br-validations, momentjs) - angular-input-masks-br.js: provides only global and BR directives, and does not include external dependencies (string-mask, br-validations, momentjs) - angular-input-masks-us.js: provides only global and US directives, and does not include external dependencies (string-mask, br-validations, momentjs) +- angular-input-masks-fr.js: provides only global and FR directives, and does not include external dependencies (string-mask, br-validations, momentjs) - angular-input-masks.js: provides all directives, and does not include external dependencies (string-mask, br-validations, momentjs) If you are using npm with browserify: @@ -228,6 +230,7 @@ If you are using npm with browserify: - ```require('angular-input-masks')```: provides all directives - ```require('angular-input-masks/br')```: only global and BR directives - ```require('angular-input-masks/us')```: only global and US directives +- ```require('angular-input-masks/fr')```: only global and FR directives ## Filters diff --git a/demo/fr.html b/demo/fr.html new file mode 100644 index 00000000..21755d97 --- /dev/null +++ b/demo/fr.html @@ -0,0 +1,27 @@ + + + + + Angular Mask FR Demo + + + + + + +
+

ui-fr-phone-number

+
+ {{phoneNumber}} - {{form.phoneNumberTest.$valid}}
+
+
+ {{initializedPhoneNumber}} - {{form.initializedPhoneNumberTest.$valid}}
+
+
+ + diff --git a/fr.js b/fr.js new file mode 100644 index 00000000..f6538579 --- /dev/null +++ b/fr.js @@ -0,0 +1 @@ +module.exports = require('./src/angular-input-masks.fr'); diff --git a/fr.test.js b/fr.test.js new file mode 100644 index 00000000..dc8dcd0f --- /dev/null +++ b/fr.test.js @@ -0,0 +1,9 @@ +describe('angular-input-masks-standalone', function () { + var moduleName = require('./fr.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 4b9a1577..406f9914 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -59,11 +59,15 @@ gulp.task('build', ['build-dependencies'], function() { debug: false, bundleExternal: false }, { - fileName: 'angular-input-masks.us.js', + fileName: 'angular-input-masks.ch.js', debug: false, bundleExternal: false }, { - fileName: 'angular-input-masks.ch.js', + fileName: 'angular-input-masks.fr.js', + debug: false, + bundleExternal: false + }, { + fileName: 'angular-input-masks.us.js', debug: false, bundleExternal: false }, { diff --git a/package.json b/package.json index efed5627..8f70ed1c 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,8 @@ "releases/", "index.js", "br.js", + "ch.js", + "fr.js", "us.js", "LICENSE", "CHANGELOG.md", diff --git a/src/angular-input-masks.fr.js b/src/angular-input-masks.fr.js new file mode 100644 index 00000000..4cebe2b0 --- /dev/null +++ b/src/angular-input-masks.fr.js @@ -0,0 +1,4 @@ +module.exports = angular.module('ui.utils.masks', [ + require('./global/global-masks'), + require('./fr/fr-masks') +]).name; diff --git a/src/angular-input-masks.js b/src/angular-input-masks.js index 293518a7..bdf2ca24 100644 --- a/src/angular-input-masks.js +++ b/src/angular-input-masks.js @@ -3,6 +3,7 @@ module.exports = angular.module('ui.utils.masks', [ require('./global/global-masks'), require('./br/br-masks'), - require('./us/us-masks'), - require('./ch/ch-masks') + require('./ch/ch-masks'), + require('./fr/fr-masks'), + require('./us/us-masks') ]).name; diff --git a/src/fr/fr-masks.js b/src/fr/fr-masks.js new file mode 100644 index 00000000..b9ec3c6b --- /dev/null +++ b/src/fr/fr-masks.js @@ -0,0 +1,8 @@ +'use strict'; + +var m = angular.module('ui.utils.masks.fr', [ + require('../helpers') +]) + .directive('uiFrPhoneNumber', require('./phone/fr-phone')); + +module.exports = m.name; diff --git a/src/fr/phone/fr-phone.html b/src/fr/phone/fr-phone.html new file mode 100644 index 00000000..dabc1ee4 --- /dev/null +++ b/src/fr/phone/fr-phone.html @@ -0,0 +1,29 @@ + + + + + FR Phone Number Spec + + + + + + +
+

ui-fr-phone-number

+
+ {{phoneNumber}} - {{form.phoneNumberTest.$valid}} + +
+
+ +
+ {{initializedPhoneNumber}} - {{form.initializedPhoneNumberTest.$valid}}
+
+ + diff --git a/src/fr/phone/fr-phone.js b/src/fr/phone/fr-phone.js new file mode 100644 index 00000000..2b5c1646 --- /dev/null +++ b/src/fr/phone/fr-phone.js @@ -0,0 +1,25 @@ +'use strict'; + +var StringMask = require('string-mask'); +var maskFactory = require('../../libs/mask-factory'); + +var phoneMaskFR = new StringMask('00 00 00 00 00'); + +module.exports = maskFactory({ + clearValue: function(rawValue) { + return rawValue.toString().replace(/[^0-9]/g, '').slice(0, 10); + }, + format: function(cleanValue) { + var formattedValue; + + formattedValue = phoneMaskFR.apply(cleanValue) || ''; + + return formattedValue.trim().replace(/[^0-9]$/, ''); + }, + validations: { + frPhoneNumber: function(value) { + var valueLength = value && value.toString().length; + return valueLength === 10; + } + } +}); diff --git a/src/fr/phone/fr-phone.spec.js b/src/fr/phone/fr-phone.spec.js new file mode 100644 index 00000000..18f710c6 --- /dev/null +++ b/src/fr/phone/fr-phone.spec.js @@ -0,0 +1,64 @@ +'use strict'; + +describe('ui.utils.masks.fr.phone', function() { + it('should load the demo page', function() { + browser.get('/src/fr/phone/fr-phone.html'); + expect(browser.getTitle()).toEqual('FR Phone Number Spec'); + }); + + describe('ui-fr-phone-number:', function() { + var runTests = function(input, value) { + 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 56 7', modelValue:'1234567'}, + {key:'8', viewValue:'12 34 56 78', modelValue:'12345678'}, + {key:'9', viewValue:'12 34 56 78 9', modelValue:'123456789'}, + {key:'0', viewValue:'12 34 56 78 90', modelValue:'1234567890'}, + {key:'1', viewValue:'12 34 56 78 90', modelValue:'1234567890'}, + {key:BS, viewValue:'12 34 56 78 9', modelValue:'123456789'}, + {key:BS, viewValue:'12 34 56 78 ', modelValue:'12345678'}, + {key:BS, viewValue:'12 34 56 78', modelValue:'12345678'}, + {key:BS, viewValue:'12 34 56 7', modelValue:'1234567'}, + {key:BS, viewValue:'12 34 56 ', modelValue:'123456'}, + {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:''}, + ]; + + 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 while the user is typing:', function() { + var input = element(by.id('fr-phone-input')), + value = element(by.id('fr-phone-value')); + + runTests(input, value); + }); + + it('should apply a phone number mask in a model with default value:', function() { + var input = element(by.id('init-fr-phone-input')), + value = element(by.id('init-fr-phone-value')); + + expect(input.getAttribute('value')).toEqual('31 33 53 67 67'); + input.clear(); + + runTests(input, value); + }); + }); +}); \ No newline at end of file diff --git a/src/fr/phone/fr-phone.test.js b/src/fr/phone/fr-phone.test.js new file mode 100644 index 00000000..858302d4 --- /dev/null +++ b/src/fr/phone/fr-phone.test.js @@ -0,0 +1,53 @@ +'use strict'; + +require('../fr-masks'); + +describe('ui-fr-phone-mask', function() { + beforeEach(angular.mock.module('ui.utils.masks.fr')); + + 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 (4+10D)', function() { + var input = TestUtil.compile('', { + model: '3011201034' + }); + + var model = input.controller('ngModel'); + expect(model.$viewValue).toBe('30 11 20 10 34'); + }); + + 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 63 24', modelValue:'23346324'}, + ]; + + tests.forEach(function(test) { + input.val(test.value).triggerHandler('input'); + expect(model.$viewValue).toBe(test.viewValue); + expect(model.$modelValue).toBe(test.modelValue); + }); + }); +});