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 () { + + }); +}); +