├── .editorconfig
├── .gitignore
├── .jshintrc
├── .travis.yml
├── Gruntfile.js
├── LICENSE
├── README.md
├── bower.json
├── dist
└── ng-filters.js
├── karma.conf.js
├── karma.underscore.conf.js
├── package.json
└── src
├── angular-filters.js
├── bytes
├── bytes-filter-spec.js
└── bytes-filter.js
├── join
├── join-filter-spec.js
└── join-filter.js
├── percentage
├── percentage-filter-spec.js
└── percentage-filter.js
├── replace
├── replace-filter-spec.js
└── replace-filter.js
├── reverse
├── reverse-filter-spec.js
└── reverse-filter.js
└── toSpacedWords
├── to-spaced-words-filter-spec.js
└── to-spaced-words-filter.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib
2 | bower_components
3 | node_modules
4 | /.idea
5 |
6 | *.log
7 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": false,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": true,
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "boss": true,
11 | "eqnull": true,
12 | "browser": true,
13 | "smarttabs": true,
14 | "globals": {
15 | "jQuery": true,
16 | "angular": true,
17 | "console": true,
18 | "$": true,
19 | "_": true,
20 | "moment": true,
21 | "describe": true,
22 | "beforeEach": true,
23 | "module": true,
24 | "inject": true,
25 | "it": true,
26 | "expect": true,
27 | "xdescribe": true,
28 | "xit": true,
29 | "spyOn": true
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.10"
4 |
5 | before_script:
6 | - export DISPLAY=:99.0
7 | - sh -e /etc/init.d/xvfb start
8 | - 'npm install -g bower grunt-cli'
9 | - 'bower install --config.interactive=false'
10 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | 'use strict';
3 |
4 | // Project configuration.
5 | grunt.initConfig({
6 | pkg: grunt.file.readJSON('package.json'),
7 | meta: {
8 | banner: [
9 | '/**',
10 | ' * <%= pkg.description %>',
11 | ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>' +
12 | ' * @link <%= pkg.homepage %>',
13 | ' * @author <%= pkg.author %>',
14 | ' * @license MIT License, http://www.opensource.org/licenses/MIT',
15 | ' */',
16 | ''
17 | ].join('\n')
18 | },
19 | dirs: {
20 | dest: 'dist'
21 | },
22 | concat: {
23 | options: {
24 | banner: '<%= meta.banner %>'
25 | },
26 | dist: {
27 | src: ['src/angular-filters.js', 'src/**/*-filter.js'],
28 | dest: '<%= dirs.dest %>/<%= pkg.name %>.js'
29 | }
30 | },
31 | bowerInstall: {
32 | install: {
33 | }
34 | },
35 | jshint: {
36 | files: ['Gruntfile.js', 'src/angular-filters.js', 'src/**/*.js'],
37 | options: {
38 | jshintrc: true
39 | }
40 | },
41 | karma: {
42 | options: {
43 | configFile: 'karma.conf.js'
44 | },
45 | build: {
46 | singleRun: true,
47 | autoWatch: false
48 | },
49 | debug: {
50 | singleRun: false,
51 | autoWatch: true,
52 | browsers: ['Chrome']
53 | },
54 | travis: {
55 | singleRun: true,
56 | autoWatch: false,
57 | browsers: ['Firefox']
58 | },
59 | travisUnderscore: {
60 | singleRun: true,
61 | autoWatch: false,
62 | browsers: ['Firefox'],
63 | configFile: 'karma.underscore.conf.js'
64 | },
65 | buildUnderscore: {
66 | configFile: 'karma.underscore.conf.js',
67 | singleRun: true,
68 | autoWatch: false
69 | },
70 | dev: {
71 | autoWatch: true
72 | }
73 | },
74 | changelog: {
75 | options: {
76 | dest: 'CHANGELOG.md'
77 | }
78 | }
79 | });
80 |
81 | // Load the plugin that provides the "jshint" task.
82 | grunt.loadNpmTasks('grunt-contrib-jshint');
83 |
84 | // Load the plugin that provides the "concat" task.
85 | grunt.loadNpmTasks('grunt-contrib-concat');
86 |
87 | grunt.loadNpmTasks('grunt-bower-task');
88 |
89 | grunt.renameTask('bower', 'bowerInstall');
90 |
91 | grunt.loadNpmTasks('grunt-karma');
92 | grunt.loadNpmTasks('grunt-conventional-changelog');
93 |
94 | // Default task.
95 | grunt.registerTask('default', ['build']);
96 |
97 | // Build task.
98 | grunt.registerTask('build', ['bowerInstall', /* 'test', */ 'concat']);
99 |
100 | grunt.registerTask('test', ['karma:build', 'karma:buildUnderscore']);
101 |
102 | grunt.registerTask('test-debug', ['karma:debug']);
103 |
104 | grunt.registerTask('travis', ['karma:travis', 'karma:travisUnderscore']);
105 |
106 | // Provides the "bump" task.
107 | grunt.registerTask('bump', 'Increment version number', function() {
108 | var versionType = grunt.option('type');
109 | function bumpVersion(version, versionType) {
110 | var type = {patch: 2, minor: 1, major: 0},
111 | parts = version.split('.'),
112 | idx = type[versionType || 'patch'];
113 | parts[idx] = parseInt(parts[idx], 10) + 1;
114 | while(++idx < parts.length) { parts[idx] = 0; }
115 | return parts.join('.');
116 | }
117 | var version;
118 | function updateFile(file) {
119 | var json = grunt.file.readJSON(file);
120 | version = json.version = bumpVersion(json.version, versionType || 'patch');
121 | grunt.file.write(file, JSON.stringify(json, null, ' '));
122 | }
123 | updateFile('package.json');
124 | updateFile('bower.json');
125 | grunt.log.ok('Version bumped to ' + version);
126 | });
127 | };
128 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Blake Niemyjski
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ng-filters
2 | [](http://bower.io/search/?q=ng-filters)
3 | [](https://slack.exceptionless.com)
4 | [](https://donorbox.org/exceptionless)
5 |
6 | Useful filters for AngularJS
7 |
8 | Install
9 | -------
10 | ```html
11 | bower install ng-filters --save-dev
12 | ```
13 |
14 | Usage
15 | -------
16 |
17 | ###bytes
18 | Prints a number in a friendly byte representation
19 |
20 | ```html
21 | {{1536 | bytes}}
22 | {{'1536' | bytes}}
23 | {{1536 | bytes:2}}
24 |
25 | Result:
26 | 1.5 kB
27 | 1.5 kB
28 | 1.50 kB
29 | ```
30 |
31 | ###join
32 | Joins an array into a string
33 |
34 | ```html
35 | {{[1, 2] | join}}
36 | {{[1, null, 2, undefined] | join}}
37 | {{[1, 2] | join:', '}}
38 |
39 | Result:
40 | 1,2
41 | 1,2
42 | 1, 2
43 | ```
44 |
45 | ###percentage
46 | Returns a number formatted as a percentage. Numbers between 0 and 1 will be rounded up to 10th decimal place.
47 |
48 | ```html
49 | {{123 | percentage}}
50 | {{null | percentage}}
51 | {{60.0 | percentage}}
52 | {{0 | percentage}}
53 | {{0.000001 | percentage}}
54 | {{100.000001 | percentage:100}}
55 |
56 | Result:
57 | 123%
58 | 0%
59 | 60%
60 | 0%
61 | 0.1%
62 | 100%
63 | ```
64 |
65 | ###replace
66 | Replaces string content
67 |
68 | ```html
69 | {{'blake' | replace:'b':'B'}}
70 |
71 | Result:
72 | Blake
73 | ```
74 |
75 | ###reverse
76 | Reverses as string or array
77 |
78 | ```html
79 | {{'blake' | reverse}}
80 | {{[1, 2] | reverse}}
81 |
82 | Result:
83 | ekalb
84 | [2, 1]
85 | ```
86 |
87 | ###toSpacedWords
88 | Splits a single word into multiple words
89 |
90 | ```html
91 | {{'blake' | toSpacedWords}}
92 | {{'blakeIsAwesome' | toSpacedWords}}
93 |
94 | Result:
95 | Blake
96 | Blake Is Awesome
97 | ```
98 |
99 | Acknowledgements
100 | -------
101 | I used [Restangular](https://github.com/mgonto/restangular) as a template for this project as no one has yet to create a project template for new projects.
102 | The bytes filter originated from [Thom Seddon](https://gist.github.com/thomseddon/3511330) before some improvements were made.
103 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-filters",
3 | "version": "1.3.1",
4 | "main": "./dist/ng-filters.js",
5 | "description": "Useful filters for AngularJS",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/exceptionless/ng-filters.git"
9 | },
10 | "dependencies": {
11 | "angular": "^1.5.8",
12 | "angular-mocks": "^1.5.8"
13 | },
14 | "ignore": [
15 | "node_modules"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/dist/ng-filters.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Useful filters for AngularJS
3 | * @version v1.3.1 - 2016-09-26 * @link https://github.com/exceptionless/ng-filters
4 | * @author Blake Niemyjski
5 | * @license MIT License, http://www.opensource.org/licenses/MIT
6 | */
7 | (function () {
8 | 'use strict';
9 |
10 | angular.module('angular-filters', []);
11 | }());
12 |
13 | (function () {
14 | 'use strict';
15 |
16 | angular.module('angular-filters')
17 | .filter('bytes', [function () {
18 | return function(bytes, precision) {
19 | if (typeof bytes !== 'number') {
20 | bytes = parseFloat(bytes);
21 | }
22 |
23 | if (bytes === 0) {
24 | return '0 B';
25 | } else if (isNaN(bytes) || !isFinite(bytes)) {
26 | return '-';
27 | }
28 |
29 | var isNegative = bytes < 0;
30 | if (isNegative) {
31 | bytes = -bytes;
32 | }
33 |
34 | if (typeof precision !== 'number') {
35 | precision = parseFloat(precision);
36 | }
37 |
38 | if (isNaN(precision) || !isFinite(precision)) {
39 | precision = 1;
40 | }
41 |
42 | var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
43 | var exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
44 | var number = (bytes / Math.pow(1024, Math.floor(exponent))).toFixed(precision);
45 |
46 | return (isNegative ? '-' : '') + number + ' ' + units[exponent];
47 | };
48 | }]);
49 | }());
50 |
51 | (function () {
52 | 'use strict';
53 |
54 | angular.module('angular-filters')
55 | .filter('join', [function () {
56 | return function(input, separator) {
57 | if (!Array.isArray(input)){
58 | return input;
59 | }
60 |
61 | var filtered = [];
62 | input.forEach(function (item) {
63 | if (item){
64 | filtered.push(item);
65 | }
66 | });
67 |
68 | return filtered.join(separator || ',');
69 | };
70 | }]);
71 | }());
72 |
73 | (function () {
74 | 'use strict';
75 |
76 | angular.module('angular-filters')
77 | .filter('percentage', ['$filter', function ($filter) {
78 | function roundUpToNextTenth(input) {
79 | input = parseFloat(input.toFixed(5));
80 |
81 | // Shift
82 | input = input.toString().split('e');
83 | input = Math.ceil(+(input[0] + 'e' + (input[1] ? (+input[1] + 1) : 1)));
84 | // Shift back
85 | input = input.toString().split('e');
86 |
87 | return +(input[0] + 'e' + (input[1] ? (+input[1] - 1) : -1));
88 | }
89 |
90 | return function(input, max) {
91 | input = parseFloat(input);
92 | if (!isFinite(input)) {
93 | return '0%';
94 | }
95 |
96 | input = Math.floor(input) + roundUpToNextTenth(input - Math.floor(input));
97 | max = parseFloat(max);
98 | if (isFinite(max) && input > max) {
99 | return max + '%';
100 | }
101 |
102 | return parseFloat($filter('number')(input, (input % 1 === 0) ? 0 : 1)) + '%';
103 | };
104 | }]);
105 | }());
106 |
107 | (function () {
108 | 'use strict';
109 |
110 | angular.module('angular-filters')
111 | .filter('replace', [function () {
112 | function isString(input) {
113 | return typeof input === 'string' || input instanceof String;
114 | }
115 |
116 | return function(input, searchValue, newValue) {
117 | if (!isString(input) || !isString(searchValue) || !isString(newValue))
118 | return input;
119 |
120 | return input.split(searchValue).join(newValue);
121 | };
122 | }]);
123 | }());
124 |
125 | (function () {
126 | 'use strict';
127 |
128 | angular.module('angular-filters')
129 | .filter('reverse', [function () {
130 | function reverseArray(items) {
131 | return items.slice().reverse();
132 | }
133 |
134 | function reverseString(input) {
135 | var result = '';
136 | for (var i = 0; i < input.length; i++) {
137 | result = input.charAt(i) + result;
138 | }
139 |
140 | return result;
141 | }
142 |
143 | return function(input) {
144 | if (Array.isArray(input)){
145 | return reverseArray(input);
146 | }
147 |
148 | if (typeof input === 'string' || input instanceof String) {
149 | return reverseString(input);
150 | }
151 |
152 | return input;
153 | };
154 | }]);
155 | }());
156 |
157 | (function () {
158 | 'use strict';
159 |
160 | angular.module('angular-filters')
161 | .filter('toSpacedWords', [function () {
162 | function toSpacedWords(input) {
163 | if (!input.match(/\d+|__/g)) {
164 | input = input.replace(/([a-z])([A-Z])/g, '$1 $2');
165 | input = input.length > 1 ? input.charAt(0).toUpperCase() + input.slice(1) : input;
166 | }
167 |
168 | return input;
169 | }
170 |
171 | return function(input) {
172 | if (!input) {
173 | return input;
174 | }
175 |
176 | if (typeof input === 'string' || input instanceof String) {
177 | return toSpacedWords(input);
178 | }
179 |
180 | return input;
181 | };
182 | }]);
183 | }());
184 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | basePath: '',
4 | frameworks: ["jasmine"],
5 |
6 | files: [
7 | 'node_modules/angular/angular.js',
8 | 'node_modules/angular-mocks/angular-mocks.js',
9 | 'src/angular-filters.js',
10 | 'src/**/*.js'
11 | ],
12 |
13 | exclude: [],
14 | reporters: ['mocha'],
15 | port: 9876,
16 | runnerPort: 9100,
17 | colors: true,
18 |
19 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
20 | logLevel: config.LOG_WARN,
21 | autoWatch: true,
22 |
23 | browsers: ['PhantomJS'],
24 |
25 | captureTimeout: 60000,
26 | singleRun: true
27 | });
28 | };
29 |
--------------------------------------------------------------------------------
/karma.underscore.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Fri Aug 09 2013 14:14:35 GMT-0500 (CDT)
3 |
4 | module.exports = function(config) {
5 | config.set({
6 | // base path, that will be used to resolve files and exclude
7 | basePath: '',
8 | frameworks: ["jasmine"],
9 |
10 | // list of files / patterns to load in the browser
11 | files: [
12 | 'bower_components/angular/angular.js',
13 | 'bower_components/angular-mocks/angular-mocks.js',
14 | 'src/angular-filters.js',
15 | 'src/**/*.js'
16 | ],
17 |
18 | // list of files to exclude
19 | exclude: [],
20 |
21 | // test results reporter to use
22 | // possible values: 'dots', 'progress', 'junit'
23 | reporters: ['progress'],
24 |
25 | // web server port
26 | port: 9877,
27 |
28 | // cli runner port
29 | runnerPort: 9101,
30 |
31 | // enable / disable colors in the output (reporters and logs)
32 | colors: true,
33 |
34 | // level of logging
35 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
36 | logLevel: config.LOG_INFO,
37 |
38 | // enable / disable watching file and executing tests whenever any file changes
39 | autoWatch: true,
40 |
41 | // Start these browsers, currently available:
42 | // - Chrome
43 | // - ChromeCanary
44 | // - Firefox
45 | // - Opera
46 | // - Safari (only Mac)
47 | // - PhantomJS
48 | // - IE (only Windows)
49 | browsers: ['PhantomJS'],
50 |
51 | // If browser does not capture in given timeout [ms], kill it
52 | captureTimeout: 60000,
53 |
54 | // Continuous Integration mode
55 | // if true, it capture browsers, run tests and exit
56 | singleRun: true
57 | });
58 | };
59 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng-filters",
3 | "description": "Useful filters for AngularJS",
4 | "version": "1.3.1",
5 | "filename": "ng-filters.js",
6 | "main": "./dist/ng-filters.js",
7 | "homepage": "https://github.com/exceptionless/ng-filters",
8 | "author": "Blake Niemyjski ",
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/exceptionless/ng-filters.git"
12 | },
13 | "keywords": [
14 | "angular",
15 | "client",
16 | "browser",
17 | "filter",
18 | "bytes",
19 | "join",
20 | "replace",
21 | "reverse"
22 | ],
23 | "maintainers": [
24 | {
25 | "name": "Blake Niemyjski",
26 | "website": "http://niemyjski.com"
27 | }
28 | ],
29 | "dependencies": {
30 | "angular": "^1.5.8",
31 | "angular-mocks": "^1.5.8"
32 | },
33 | "devDependencies": {
34 | "grunt": "1.0.1",
35 | "grunt-bower": "0.21",
36 | "grunt-bower-task": "0.4",
37 | "grunt-cli": "1.2.0",
38 | "grunt-contrib-concat": "1.0",
39 | "grunt-contrib-jshint": "1.0",
40 | "grunt-conventional-changelog": "6.1.0",
41 | "grunt-karma": "2.0",
42 | "jasmine-core": "2.5.2",
43 | "karma": "1.3.0",
44 | "karma-chrome-launcher": "^2.0.0",
45 | "karma-jasmine": "1.0.2",
46 | "karma-mocha-reporter": "2.2.0",
47 | "karma-phantomjs-launcher": "1.0.2",
48 | "phantomjs-prebuilt": "2.1.12"
49 | },
50 | "scripts": {
51 | "test": "grunt test --verbose"
52 | },
53 | "license": "MIT"
54 | }
55 |
--------------------------------------------------------------------------------
/src/angular-filters.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters', []);
5 | }());
6 |
--------------------------------------------------------------------------------
/src/bytes/bytes-filter-spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: bytes', function() {
2 | beforeEach(module('angular-filters'));
3 |
4 | // initialize a new instance of the filter before each test
5 | var byte;
6 | beforeEach(inject(function ($filter) {
7 | byte = $filter('bytes');
8 | }));
9 |
10 | it('should return nothing when there is no filesize', function () {
11 | expect(byte('text')).toBe('-');
12 | });
13 |
14 | it('should round the filesize based on the configured precision', function () {
15 | var size = 1024 + 512;
16 | expect(byte(size)).toBe('1.5 kB');
17 | expect(byte(size, 2)).toBe('1.50 kB');
18 | });
19 |
20 | it('should parse string numbers into byte', function () {
21 | expect(byte('0', 0)).toBe('0 B');
22 | expect(byte('10', 0)).toBe('10 B');
23 |
24 | var size = 1024 + 512;
25 | expect(byte(size, '2')).toBe('1.50 kB');
26 | });
27 |
28 | it('should recognize zero byte', function () {
29 | expect(byte(0, 0)).toBe('0 B');
30 | });
31 |
32 | it('should recognize negative byte', function () {
33 | expect(byte(-1, 0)).toBe('-1 B');
34 | });
35 |
36 | it('should recognize byte', function () {
37 | expect(byte(1, 0)).toBe('1 B');
38 | });
39 |
40 | it('should recognize kilobyte', function () {
41 | expect(byte(Math.pow(1024, 1), 0)).toBe('1 kB');
42 | });
43 |
44 | it('should recognize megabyte', function () {
45 | expect(byte(Math.pow(1024, 2), 0)).toBe('1 MB');
46 | });
47 |
48 | it('should recognize gigabyte', function () {
49 | expect(byte(Math.pow(1024, 3), 0)).toBe('1 GB');
50 | });
51 |
52 | it('should recognize terabyte', function () {
53 | expect(byte(Math.pow(1024, 4), 0)).toBe('1 TB');
54 | });
55 |
56 | it('should recognize petabyte', function () {
57 | expect(byte(Math.pow(1024, 5), 0)).toBe('1 PB');
58 | });
59 |
60 | it('should recognize exabyte', function () {
61 | expect(byte(Math.pow(1024, 6), 0)).toBe('1 EB');
62 | });
63 |
64 | it('should recognize zettabyte', function () {
65 | expect(byte(Math.pow(1024, 7), 0)).toBe('1 ZB');
66 | });
67 |
68 | it('should recognize yottabyte', function () {
69 | expect(byte(Math.pow(1024, 8), 0)).toBe('1 YB');
70 | });
71 | });
72 |
--------------------------------------------------------------------------------
/src/bytes/bytes-filter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters')
5 | .filter('bytes', [function () {
6 | return function(bytes, precision) {
7 | if (typeof bytes !== 'number') {
8 | bytes = parseFloat(bytes);
9 | }
10 |
11 | if (bytes === 0) {
12 | return '0 B';
13 | } else if (isNaN(bytes) || !isFinite(bytes)) {
14 | return '-';
15 | }
16 |
17 | var isNegative = bytes < 0;
18 | if (isNegative) {
19 | bytes = -bytes;
20 | }
21 |
22 | if (typeof precision !== 'number') {
23 | precision = parseFloat(precision);
24 | }
25 |
26 | if (isNaN(precision) || !isFinite(precision)) {
27 | precision = 1;
28 | }
29 |
30 | var units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
31 | var exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
32 | var number = (bytes / Math.pow(1024, Math.floor(exponent))).toFixed(precision);
33 |
34 | return (isNegative ? '-' : '') + number + ' ' + units[exponent];
35 | };
36 | }]);
37 | }());
38 |
--------------------------------------------------------------------------------
/src/join/join-filter-spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: join', function() {
2 | beforeEach(module('angular-filters'));
3 |
4 | // initialize a new instance of the filter before each test
5 | var join;
6 | beforeEach(inject(function ($filter) {
7 | join = $filter('join');
8 | }));
9 |
10 | it('should return undefined when nothing is passed in', function () {
11 | expect(join()).toBe(undefined);
12 | });
13 |
14 | it('should return null when null is passed in', function () {
15 | expect(join(null)).toBe(null);
16 | });
17 |
18 | it('should join array and filter null and undefined values', function () {
19 | expect(join([1, null, 2, undefined])).toBe('1,2');
20 | });
21 |
22 | it('should join array', function () {
23 | expect(join([1, 2])).toBe('1,2');
24 | expect(join([1, 2], ', ')).toBe('1, 2');
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/src/join/join-filter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters')
5 | .filter('join', [function () {
6 | return function(input, separator) {
7 | if (!Array.isArray(input)){
8 | return input;
9 | }
10 |
11 | var filtered = [];
12 | input.forEach(function (item) {
13 | if (item){
14 | filtered.push(item);
15 | }
16 | });
17 |
18 | return filtered.join(separator || ',');
19 | };
20 | }]);
21 | }());
22 |
--------------------------------------------------------------------------------
/src/percentage/percentage-filter-spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: percentage', function() {
2 | beforeEach(module('angular-filters'));
3 |
4 | // initialize a new instance of the filter before each test
5 | var percentage;
6 | beforeEach(inject(function ($filter) {
7 | percentage = $filter('percentage');
8 | }));
9 |
10 | it('should return 0% when invalid value is passed in', function () {
11 | expect(percentage()).toBe('0%');
12 | expect(percentage(null)).toBe('0%');
13 | expect(percentage(true)).toBe('0%');
14 | expect(percentage(false)).toBe('0%');
15 | expect(percentage('')).toBe('0%');
16 | });
17 |
18 | it('should return number % when number is passed in', function () {
19 | expect(percentage(123)).toBe('123%');
20 | });
21 |
22 | it('should return rounded %', function () {
23 | expect(percentage(0)).toBe('0%');
24 | expect(percentage(0.00000)).toBe('0%');
25 | expect(percentage(1)).toBe('1%');
26 | expect(percentage(2)).toBe('2%');
27 | expect(percentage(2.11)).toBe('2.2%');
28 | expect(percentage(0.99)).toBe('1%');
29 | expect(percentage(0.000001)).toBe('0%');
30 | expect(percentage(0.00001)).toBe('0.1%');
31 | expect(percentage(0.0001)).toBe('0.1%');
32 | expect(percentage(0.001)).toBe('0.1%');
33 | expect(percentage(0.01)).toBe('0.1%');
34 | expect(percentage(0.1)).toBe('0.1%');
35 | expect(percentage(0.6)).toBe('0.6%');
36 | expect(percentage(0.61)).toBe('0.7%');
37 | expect(percentage(100.1)).toBe('100.1%');
38 | expect(percentage(100.01)).toBe('100.1%');
39 | });
40 |
41 | it('should return rounded % with max', function () {
42 | expect(percentage(0.1, 0.01)).toBe('0.01%');
43 | expect(percentage(0.6, 0.5)).toBe('0.5%');
44 | expect(percentage(0.6, 0.7)).toBe('0.6%');
45 | expect(percentage(99.9, 100)).toBe('99.9%');
46 | expect(percentage(99.99, 99.99)).toBe('99.99%');
47 | expect(percentage(99.99, 100)).toBe('100%');
48 | expect(percentage(100, 100)).toBe('100%');
49 | expect(percentage(100.00001, 100)).toBe('100%');
50 | expect(percentage(100.00001, 100.0)).toBe('100%');
51 | expect(percentage(101, 100)).toBe('100%');
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/src/percentage/percentage-filter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters')
5 | .filter('percentage', ['$filter', function ($filter) {
6 | function roundUpToNextTenth(input) {
7 | input = parseFloat(input.toFixed(5));
8 |
9 | // Shift
10 | input = input.toString().split('e');
11 | input = Math.ceil(+(input[0] + 'e' + (input[1] ? (+input[1] + 1) : 1)));
12 | // Shift back
13 | input = input.toString().split('e');
14 |
15 | return +(input[0] + 'e' + (input[1] ? (+input[1] - 1) : -1));
16 | }
17 |
18 | return function(input, max) {
19 | input = parseFloat(input);
20 | if (!isFinite(input)) {
21 | return '0%';
22 | }
23 |
24 | input = Math.floor(input) + roundUpToNextTenth(input - Math.floor(input));
25 | max = parseFloat(max);
26 | if (isFinite(max) && input > max) {
27 | return max + '%';
28 | }
29 |
30 | return parseFloat($filter('number')(input, (input % 1 === 0) ? 0 : 1)) + '%';
31 | };
32 | }]);
33 | }());
34 |
--------------------------------------------------------------------------------
/src/replace/replace-filter-spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: replace', function() {
2 | beforeEach(module('angular-filters'));
3 |
4 | // initialize a new instance of the filter before each test
5 | var replace;
6 | beforeEach(inject(function ($filter) {
7 | replace = $filter('replace');
8 | }));
9 |
10 | it('should return undefined when nothing is passed in', function () {
11 | expect(replace()).toBe(undefined);
12 | });
13 |
14 | it('should return null when null is passed in', function () {
15 | expect(replace(null)).toBe(null);
16 | });
17 |
18 | it('should return number when number is passed in', function () {
19 | expect(replace(123)).toBe(123);
20 | });
21 |
22 | it('should return object when object is passed in', function () {
23 | expect(replace({ name: 'blake' })).toEqual({ name: 'blake' });
24 | });
25 |
26 | it('should return empty string', function () {
27 | expect(replace('')).toBe('');
28 | });
29 |
30 | it('should return initial value when there are invalid arguments', function () {
31 | expect(replace('blake')).toBe('blake');
32 | expect(replace('blake', null)).toBe('blake');
33 | expect(replace('blake', 1)).toBe('blake');
34 | expect(replace('blake', null, null)).toBe('blake');
35 | expect(replace('blake', 1, 1)).toBe('blake');
36 | });
37 |
38 | it('should replace b with B', function () {
39 | expect(replace('blake blake', 'b', 'B')).toBe('Blake Blake');
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/src/replace/replace-filter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters')
5 | .filter('replace', [function () {
6 | function isString(input) {
7 | return typeof input === 'string' || input instanceof String;
8 | }
9 |
10 | return function(input, searchValue, newValue) {
11 | if (!isString(input) || !isString(searchValue) || !isString(newValue))
12 | return input;
13 |
14 | return input.split(searchValue).join(newValue);
15 | };
16 | }]);
17 | }());
18 |
--------------------------------------------------------------------------------
/src/reverse/reverse-filter-spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: reverse', function() {
2 | beforeEach(module('angular-filters'));
3 |
4 | // initialize a new instance of the filter before each test
5 | var reverse;
6 | beforeEach(inject(function ($filter) {
7 | reverse = $filter('reverse');
8 | }));
9 |
10 | it('should return undefined when nothing is passed in', function () {
11 | expect(reverse()).toBe(undefined);
12 | });
13 |
14 | it('should return null when null is passed in', function () {
15 | expect(reverse(null)).toBe(null);
16 | });
17 |
18 | it('should return number when number is passed in', function () {
19 | expect(reverse(123)).toBe(123);
20 | });
21 |
22 | it('should return object when object is passed in', function () {
23 | expect(reverse({ name: 'blake' })).toEqual({ name: 'blake' });
24 | });
25 |
26 | it('should return empty array', function () {
27 | expect(reverse([])).toEqual([]);
28 | });
29 |
30 | it('should reverse array', function () {
31 | expect(reverse([1, 2])).toEqual([2, 1]);
32 | });
33 |
34 | it('should return empty string', function () {
35 | expect(reverse('')).toBe('');
36 | });
37 |
38 | it('should reverse string', function () {
39 | expect(reverse('blake')).toBe('ekalb');
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/src/reverse/reverse-filter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters')
5 | .filter('reverse', [function () {
6 | function reverseArray(items) {
7 | return items.slice().reverse();
8 | }
9 |
10 | function reverseString(input) {
11 | var result = '';
12 | for (var i = 0; i < input.length; i++) {
13 | result = input.charAt(i) + result;
14 | }
15 |
16 | return result;
17 | }
18 |
19 | return function(input) {
20 | if (Array.isArray(input)){
21 | return reverseArray(input);
22 | }
23 |
24 | if (typeof input === 'string' || input instanceof String) {
25 | return reverseString(input);
26 | }
27 |
28 | return input;
29 | };
30 | }]);
31 | }());
32 |
--------------------------------------------------------------------------------
/src/toSpacedWords/to-spaced-words-filter-spec.js:
--------------------------------------------------------------------------------
1 | describe('Filter: toSpacedWords', function() {
2 | beforeEach(module('angular-filters'));
3 |
4 | // initialize a new instance of the filter before each test
5 | var toSpacedWords;
6 | beforeEach(inject(function ($filter) {
7 | toSpacedWords = $filter('toSpacedWords');
8 | }));
9 |
10 | it('should return undefined when nothing is passed in', function () {
11 | expect(toSpacedWords()).toBe(undefined);
12 | });
13 |
14 | it('should return null when null is passed in', function () {
15 | expect(toSpacedWords(null)).toBe(null);
16 | });
17 |
18 | it('should return number when number is passed in', function () {
19 | expect(toSpacedWords(123)).toBe(123);
20 | });
21 |
22 | it('should return object when object is passed in', function () {
23 | expect(toSpacedWords({ name: 'blake' })).toEqual({ name: 'blake' });
24 | });
25 |
26 | it('should return empty array', function () {
27 | expect(toSpacedWords([])).toEqual([]);
28 | });
29 |
30 | it('should toSpacedWords array', function () {
31 | expect(toSpacedWords([1, 2])).toEqual([1, 2]);
32 | });
33 |
34 | it('should return empty string', function () {
35 | expect(toSpacedWords('')).toBe('');
36 | });
37 |
38 | it('should upper case single word', function () {
39 | expect(toSpacedWords('blake')).toBe('Blake');
40 | });
41 |
42 | it('should split upper case multiple words', function () {
43 | expect(toSpacedWords('blakeNiemyjskiIsAwesome')).toBe('Blake Niemyjski Is Awesome');
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/src/toSpacedWords/to-spaced-words-filter.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | angular.module('angular-filters')
5 | .filter('toSpacedWords', [function () {
6 | function toSpacedWords(input) {
7 | if (!input.match(/\d+|__/g)) {
8 | input = input.replace(/([a-z])([A-Z])/g, '$1 $2');
9 | input = input.length > 1 ? input.charAt(0).toUpperCase() + input.slice(1) : input;
10 | }
11 |
12 | return input;
13 | }
14 |
15 | return function(input) {
16 | if (!input) {
17 | return input;
18 | }
19 |
20 | if (typeof input === 'string' || input instanceof String) {
21 | return toSpacedWords(input);
22 | }
23 |
24 | return input;
25 | };
26 | }]);
27 | }());
28 |
--------------------------------------------------------------------------------