diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7e1ac32
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+node_modules/
+bower_components/
+.idea
+coverage
+npm-debug.log
\ No newline at end of file
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..c5fe609
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,26 @@
+{
+ "node": true,
+ "browser": true,
+ "esnext": true,
+ "bitwise": true,
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "indent": 2,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "quotmark": "single",
+ "regexp": true,
+ "undef": true,
+ "unused": true,
+ "strict": true,
+ "trailing": true,
+ "smarttabs": true,
+ "maxdepth": 2,
+ "maxcomplexity": 10,
+ "globals": {
+ "angular": false
+ }
+}
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..d031e5d
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: node_js
+sudo: false
+node_js:
+ - 0.12
+ - 4
+ - 5
+ - 6
+before_script:
+ - npm run bower
+after_success:
+ - cat ./coverage/*/lcov.info | ./node_modules/coveralls/bin/coveralls.js
\ No newline at end of file
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..81cd179
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,51 @@
+/* License: MIT.
+ * Copyright (C) 2016, Cosimo Meli.
+ */
+
+'use strict';
+
+module.exports = function (grunt) {
+ // Load grunt tasks automatically
+ require('load-grunt-tasks')(grunt);
+
+ grunt.initConfig({
+ karma: {
+ unit: {
+ configFile: 'karma.conf.js',
+ singleRun: true
+ }
+ },
+ jshint: {
+ options: {
+ jshintrc: '.jshintrc'
+ },
+ all: [
+ 'Gruntfile.js',
+ 'angular-xregexp.js',
+ 'tests.js'
+ ]
+ },
+ uglify: {
+ dist: {
+ options: {
+ sourceMap: true
+ },
+ files: {
+ 'angular-xregexp.min.js': 'angular-xregexp.js'
+ }
+ }
+ }
+ });
+
+ grunt.registerTask('test', [
+ 'jshint',
+ 'karma'
+ ]);
+
+ grunt.registerTask('build', [
+ 'jshint',
+ 'uglify'
+ ]);
+
+ grunt.registerTask('default', ['build']);
+};
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..07af9ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License
+
+Copyright (c) 2016 Cosimo Meli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9c4008d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,35 @@
+angular-xregexp
+==============
+
+XRegExp validator for AngularJS.
+This library decorates ngPattern to use [XRegExp](http://xregexp.com/) for more complex regular expression.
+
+
+Installation
+------------
+
+You can choose your preferred method of installation:
+* Through bower: `bower install angular-xregexp --save`
+* Through npm: `npm install angular-xregexp xregexp --save`
+* Download from github: [angular-xregexp.min.js](https://raw.github.com/cosimomeli/angular-xregexp/master/angular-xregexp.min.js)
+
+Usage
+-----
+Include both **xregexp-all.js** and **angular-xregexp.js** in your application.
+
+```html
+
+
+```
+
+Add the module `angularXRegExp` as a dependency to your app module:
+
+```js
+var myapp = angular.module('myapp', ['angularXRegExp']);
+```
+Then just use `ng-pattern` as always.
+
+License
+----
+
+Released under the terms of the [MIT License](LICENSE).
diff --git a/angular-xregexp.js b/angular-xregexp.js
new file mode 100644
index 0000000..eaab926
--- /dev/null
+++ b/angular-xregexp.js
@@ -0,0 +1,133 @@
+/* angular-xregexp.js / v1.0.0 / (c) 2016 Cosimo Meli / MIT Licence */
+
+'format amd';
+/* global define */
+
+(function () {
+ 'use strict';
+
+ function requireXRegExp() {
+ try {
+ return require('xregexp'); // Using nw.js or browserify?
+ } catch (e) {
+ throw new Error('Please install XRegExp via npm. Please reference to: https://github.com/cosimomeli/angular-xregexp');
+ }
+ }
+
+ function angularXRegExp(angular, XRegExp) {
+
+ if (typeof XRegExp === 'undefined') {
+ if (typeof require === 'function') {
+ XRegExp = requireXRegExp();
+ } else {
+ throw new Error('XRegExp cannot be found by angular-xregexp! Please reference to: https://github.com/cosimomeli/angular-xregexp');
+ }
+ }
+
+ var NODE_TYPE_TEXT = 3;
+
+ /**
+ * @returns {string} Returns the string representation of the element.
+ */
+ function startingTag(element) {
+ element = angular.element(element).clone();
+ try {
+ // turns out IE does not let you set .html() on elements which
+ // are not allowed to have children. So we just ignore it.
+ element.empty();
+ } catch (e) {
+ }
+ var elemHtml = angular.element('
').append(element).html();
+ try {
+ return element[0].nodeType === NODE_TYPE_TEXT ? angular.lowercase(elemHtml) :
+ elemHtml.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/, function (match, nodeName) {
+ return '<' + angular.lowercase(nodeName);
+ });
+ } catch (e) {
+ return angular.lowercase(elemHtml);
+ }
+
+ }
+
+ /**
+ * New link function to replace the ngPattern one
+ */
+ function newLink(scope, elm, attr, ctrl) {
+ if (!ctrl) {
+ return;
+ }
+
+ function toXRegExp(regex) {
+ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
+ if (regex instanceof RegExp) {
+ regex = regex.toString();
+ }
+ var match = regex.match(REGEX_STRING_REGEXP);
+ if (match) {
+ return new XRegExp(match[1], match[2]);
+ }
+
+ }
+
+ var regexp, patternExp = toXRegExp(attr.ngPattern || attr.pattern);
+
+ attr.$observe('pattern', function (regex) {
+ if (angular.isString(regex) && regex.length > 0) {
+ regex = new XRegExp('^' + regex + '$');
+ } else if (regex instanceof RegExp) {
+ regex = toXRegExp(regex);
+ }
+
+ if (regex && !regex.test) {
+ throw angular.$$minErr('ngPattern')('noregexp',
+ 'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
+ regex, startingTag(elm));
+ }
+
+ regexp = regex || undefined;
+ ctrl.$validate();
+ });
+
+ ctrl.$validators.pattern = function (modelValue, viewValue) {
+ // HTML5 pattern constraint validates the input value, so we validate the viewValue
+ return ctrl.$isEmpty(viewValue) || angular.isUndefined(regexp) || regexp.test(viewValue);
+ };
+ }
+
+ /**
+ * @ngdoc overview
+ * @name angularXRegExp
+ *
+ * @description
+ * angularXRegExp module provides XRegExp functionality for angular.js apps.
+ */
+ angular.module('angularXRegExp', [])
+
+ /**
+ * @ngdoc object
+ * @name angularXRegExp.config
+ */
+ .config(['$provide', function ($provide) {
+ $provide.decorator('ngPatternDirective', ['$delegate', function ($delegate) {
+ //Replace ngPattern's link function
+ $delegate[0].compile = function () {
+ return function () {
+ newLink.apply(this, arguments);
+ };
+ };
+ return $delegate;
+ }]);
+ }]);
+
+ return 'angularXRegExp';
+ }
+
+ var isElectron = window && window.process && window.process.type;
+ if (typeof define === 'function' && define.amd) {
+ define(['angular', 'xregexp'], angularXRegExp);
+ } else if (typeof module !== 'undefined' && module && module.exports && (typeof require === 'function') && !isElectron) {
+ module.exports = angularXRegExp(require('angular'), require('xregexp'));
+ } else {
+ angularXRegExp(angular, (typeof global !== 'undefined' ? global : window).XRegExp);
+ }
+})();
diff --git a/angular-xregexp.min.js b/angular-xregexp.min.js
new file mode 100644
index 0000000..8cdbfea
--- /dev/null
+++ b/angular-xregexp.min.js
@@ -0,0 +1,2 @@
+"format amd";!function(){"use strict";function a(){try{return require("xregexp")}catch(a){throw new Error("Please install XRegExp via npm. Please reference to: https://github.com/cosimomeli/angular-xregexp")}}function b(b,c){function d(a){a=b.element(a).clone();try{a.empty()}catch(c){}var d=b.element("
").append(a).html();try{return a[0].nodeType===f?b.lowercase(d):d.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,c){return"<"+b.lowercase(c)})}catch(c){return b.lowercase(d)}}function e(a,e,f,g){function h(a){var b=/^\/(.+)\/([a-z]*)$/;a instanceof RegExp&&(a=a.toString());var d=a.match(b);if(d)return new c(d[1],d[2])}if(g){var i,j=h(f.ngPattern||f.pattern);f.$observe("pattern",function(a){if(b.isString(a)&&a.length>0?a=new c("^"+a+"$"):a instanceof RegExp&&(a=h(a)),a&&!a.test)throw b.$$minErr("ngPattern")("noregexp","Expected {0} to be a RegExp but was {1}. Element: {2}",j,a,d(e));i=a||void 0,g.$validate()}),g.$validators.pattern=function(a,c){return g.$isEmpty(c)||b.isUndefined(i)||i.test(c)}}}if("undefined"==typeof c){if("function"!=typeof require)throw new Error("XRegExp cannot be found by angular-xregexp! Please reference to: https://github.com/cosimomeli/angular-xregexp");c=a()}var f=3;return b.module("angularXRegExp",[]).config(["$provide",function(a){a.decorator("ngPatternDirective",["$delegate",function(a){return a[0].compile=function(){return function(){e.apply(this,arguments)}},a}])}]),"angularXRegExp"}var c=window&&window.process&&window.process.type;"function"==typeof define&&define.amd?define(["angular","xregexp"],b):"undefined"!=typeof module&&module&&module.exports&&"function"==typeof require&&!c?module.exports=b(require("angular"),require("xregexp")):b(angular,("undefined"!=typeof global?global:window).XRegExp)}();
+//# sourceMappingURL=angular-xregexp.min.js.map
\ No newline at end of file
diff --git a/angular-xregexp.min.js.map b/angular-xregexp.min.js.map
new file mode 100644
index 0000000..be0a181
--- /dev/null
+++ b/angular-xregexp.min.js.map
@@ -0,0 +1,73 @@
+{
+ "version": 3,
+ "sources": [
+ "angular-xregexp.js"
+ ],
+ "names": [
+ "requireXRegExp",
+ "require",
+ "e",
+ "Error",
+ "angularXRegExp",
+ "angular",
+ "XRegExp",
+ "startingTag",
+ "element",
+ "clone",
+ "empty",
+ "elemHtml",
+ "append",
+ "html",
+ "nodeType",
+ "NODE_TYPE_TEXT",
+ "lowercase",
+ "match",
+ "replace",
+ "nodeName",
+ "newLink",
+ "scope",
+ "elm",
+ "attr",
+ "ctrl",
+ "toXRegExp",
+ "regex",
+ "REGEX_STRING_REGEXP",
+ "RegExp",
+ "toString",
+ "regexp",
+ "patternExp",
+ "ngPattern",
+ "pattern",
+ "$observe",
+ "isString",
+ "length",
+ "test",
+ "$$minErr",
+ "undefined",
+ "$validate",
+ "$validators",
+ "modelValue",
+ "viewValue",
+ "$isEmpty",
+ "isUndefined",
+ "module",
+ "config",
+ "$provide",
+ "decorator",
+ "$delegate",
+ "compile",
+ "apply",
+ "this",
+ "arguments",
+ "isElectron",
+ "window",
+ "process",
+ "type",
+ "define",
+ "amd",
+ "exports",
+ "global"
+ ],
+ "mappings": "AAEA,cAGA,WACI,YAEA,SAASA,KACL,IACI,MAAOC,SAAQ,WACjB,MAAOC,GACL,KAAM,IAAIC,OAAM,uGAIxB,QAASC,GAAeC,EAASC,GAe7B,QAASC,GAAYC,GACjBA,EAAUH,EAAQG,QAAQA,GAASC,OACnC,KAGID,EAAQE,QACV,MAAOR,IAET,GAAIS,GAAWN,EAAQG,QAAQ,SAASI,OAAOJ,GAASK,MACxD,KACI,MAAOL,GAAQ,GAAGM,WAAaC,EAAiBV,EAAQW,UAAUL,GAC9DA,EAASM,MAAM,cAAc,GAAGC,QAAQ,cAAe,SAAUD,EAAOE,GACpE,MAAO,IAAMd,EAAQW,UAAUG,KAEzC,MAAOjB,GACL,MAAOG,GAAQW,UAAUL,IAQjC,QAASS,GAAQC,EAAOC,EAAKC,EAAMC,GAK/B,QAASC,GAAUC,GACf,GAAIC,GAAsB,oBACtBD,aAAiBE,UACjBF,EAAQA,EAAMG,WAElB,IAAIZ,GAAQS,EAAMT,MAAMU,EACxB,IAAIV,EACA,MAAO,IAAIX,GAAQW,EAAM,GAAIA,EAAM,IAX3C,GAAKO,EAAL,CAgBA,GAAIM,GAAQC,EAAaN,EAAUF,EAAKS,WAAaT,EAAKU,QAE1DV,GAAKW,SAAS,UAAW,SAAUR,GAO/B,GANIrB,EAAQ8B,SAAST,IAAUA,EAAMU,OAAS,EAC1CV,EAAQ,GAAIpB,GAAQ,IAAMoB,EAAQ,KAC3BA,YAAiBE,UACxBF,EAAQD,EAAUC,IAGlBA,IAAUA,EAAMW,KAChB,KAAMhC,GAAQiC,SAAS,aAAa,WAChC,wDAAyDP,EACzDL,EAAOnB,EAAYe,GAG3BQ,GAASJ,GAASa,OAClBf,EAAKgB,cAGThB,EAAKiB,YAAYR,QAAU,SAAUS,EAAYC,GAE7C,MAAOnB,GAAKoB,SAASD,IAActC,EAAQwC,YAAYf,IAAWA,EAAOO,KAAKM,KA1EtF,GAAuB,mBAAZrC,GAAyB,CAChC,GAAuB,kBAAZL,SAGP,KAAM,IAAIE,OAAM,iHAFhBG,GAAUN,IAMlB,GAAIe,GAAiB,CA+FrB,OAlBAV,GAAQyC,OAAO,qBAMVC,QAAQ,WAAY,SAAUC,GAC3BA,EAASC,UAAU,sBAAuB,YAAa,SAAUC,GAO7D,MALAA,GAAU,GAAGC,QAAU,WACnB,MAAO,YACH/B,EAAQgC,MAAMC,KAAMC,aAGrBJ,QAIZ,iBAGX,GAAIK,GAAaC,QAAUA,OAAOC,SAAWD,OAAOC,QAAQC,IACtC,mBAAXC,SAAyBA,OAAOC,IACvCD,QAAQ,UAAW,WAAYvD,GACN,mBAAX0C,SAA0BA,QAAUA,OAAOe,SAA+B,kBAAZ5D,WAA4BsD,EACxGT,OAAOe,QAAUzD,EAAeH,QAAQ,WAAYA,QAAQ,YAE5DG,EAAeC,SAA4B,mBAAXyD,QAAyBA,OAASN,QAAQlD",
+ "file": "angular-xregexp.min.js"
+}
\ No newline at end of file
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..d5db66b
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,21 @@
+{
+ "name": "angular-xregexp",
+ "description": "XRegExp validator for AngularJS",
+ "author": "Cosimo Meli",
+ "license": "MIT",
+ "homepage": "https://github.com/cosimomeli/angular-xregexp",
+ "main": "./angular-xregexp.js",
+ "ignore": [
+ ],
+ "dependencies": {
+ "angular": "^1.2.0",
+ "xregexp": "3.x"
+ },
+ "devDependencies": {
+ "angular-mocks": "1.4.x"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/cosimomeli/angular-xregexp.git"
+ }
+}
\ No newline at end of file
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..20e0624
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,30 @@
+/* License: MIT.
+ * Copyright (C) 2016 Cosimo Meli.
+ */
+
+'use strict';
+
+module.exports = function (config) {
+ config.set({
+ basePath: '',
+ frameworks: ['jasmine'],
+ logLevel: config.LOG_INFO,
+ browsers: ['PhantomJS'],
+ autoWatch: true,
+ reporters: ['dots', 'coverage'],
+ files: [
+ 'bower_components/angular/angular.js',
+ 'bower_components/xregexp/xregexp-all.js',
+ 'angular-xregexp.js',
+ 'bower_components/angular-mocks/angular-mocks.js',
+ 'tests.js'
+ ],
+ preprocessors: {
+ 'angular-xregexp.js': 'coverage'
+ },
+ coverageReporter: {
+ type: 'lcov',
+ dir: 'coverage/'
+ }
+ });
+};
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d4f0ef1
--- /dev/null
+++ b/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "angular-xregexp",
+ "version": "1.0.0",
+ "main": "angular-xregexp.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/cosimomeli/angular-xregexp.git"
+ },
+ "license": "MIT",
+ "files": [
+ "angular-xregexp.js",
+ "angular-xregexp.min.js",
+ "angular-xregexp.min.js.map",
+ "LICENSE"
+ ],
+ "dependencies": {
+ "xregexp": "3.x"
+ },
+ "devDependencies": {
+ "bower": "1.x",
+ "coveralls": "2.x",
+ "grunt": "1.x",
+ "grunt-cli": "1.x",
+ "grunt-contrib-jshint": "1.x",
+ "grunt-contrib-uglify": "1.x",
+ "grunt-karma": "0.x",
+ "jasmine-core": "2.x",
+ "phantomjs-prebuilt": "2.x",
+ "karma": "1.x",
+ "karma-coverage": "1.x",
+ "karma-jasmine": "1.x",
+ "karma-phantomjs-launcher": "1.x",
+ "load-grunt-tasks": "3.x"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "scripts": {
+ "bower": "node_modules/.bin/bower install",
+ "test": "node_modules/.bin/grunt test",
+ "build": "node_modules/.bin/grunt build"
+ }
+}
\ No newline at end of file
diff --git a/tests.js b/tests.js
new file mode 100644
index 0000000..c173210
--- /dev/null
+++ b/tests.js
@@ -0,0 +1,15 @@
+/* License: MIT.
+ * Copyright (C) 2016, Cosimo Meli.
+ */
+
+/* global describe, it*/
+
+'use strict';
+
+describe('module angularXRegExp', function () {
+ //todo TESTS
+ it('nothing', function () {
+
+ });
+});
+