├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── dist ├── angular-csv-import.js └── angular-csv-import.min.js ├── examples ├── .bowerrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── app │ ├── .buildignore │ ├── .htaccess │ ├── 404.html │ ├── favicon.ico │ ├── index.html │ ├── robots.txt │ ├── scripts │ │ ├── app.js │ │ └── controllers │ │ │ ├── about.js │ │ │ └── main.js │ ├── styles │ │ └── main.css │ └── views │ │ └── main.html ├── bower.json ├── package.json ├── source │ ├── source.csv │ └── source_es.csv └── test │ ├── .jshintrc │ ├── karma.conf.js │ └── spec │ └── controllers │ ├── about.js │ └── main.js ├── lib ├── .DS_Store ├── angular-csv-import.css └── angular-csv-import.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | bower_components/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | - 0.10 5 | before_install: 6 | - npm update npm -g -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global require, module:false*/ 2 | module.exports = function(grunt) { 3 | 'use strict'; 4 | 5 | // Load grunt tasks automatically 6 | require('load-grunt-tasks')(grunt); 7 | 8 | // Time how long tasks take. Can help when optimizing build times 9 | require('time-grunt')(grunt); 10 | 11 | // Project configuration. 12 | grunt.initConfig({ 13 | // Metadata. 14 | pkg: grunt.file.readJSON('package.json'), 15 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + 16 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' + 17 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' + 18 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + 19 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n', 20 | // Task configuration. 21 | concat: { 22 | options: { 23 | banner: '<%= banner %>', 24 | stripBanners: true 25 | }, 26 | dist: { 27 | src: ['lib/<%= pkg.name %>.js'], 28 | dest: 'dist/<%= pkg.name %>.js' 29 | }, 30 | examples: { 31 | src: ['lib/<%= pkg.name %>.js'], 32 | dest: 'examples/app/bower_components/angular-csv-import/dist/<%= pkg.name %>.js' 33 | } 34 | }, 35 | bump: { 36 | options: { 37 | files: ['package.json', 'bower.json'], 38 | updateConfigs: [], 39 | commit: true, 40 | commitMessage: 'Release v%VERSION%', 41 | commitFiles: ['package.json', 'bower.json'], 42 | createTag: true, 43 | tagName: 'v%VERSION%', 44 | tagMessage: 'Version %VERSION%', 45 | push: true, 46 | pushTo: 'origin', 47 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' 48 | } 49 | }, 50 | uglify: { 51 | options: { 52 | banner: '<%= banner %>' 53 | }, 54 | dist: { 55 | src: '<%= concat.dist.dest %>', 56 | dest: 'dist/<%= pkg.name %>.min.js' 57 | }, 58 | examples: { 59 | src: '<%= concat.dist.dest %>', 60 | dest: 'examples/app/bower_components/angular-csv-import/dist/<%= pkg.name %>.min.js' 61 | } 62 | }, 63 | jshint: { 64 | options: { 65 | curly: true, 66 | eqeqeq: true, 67 | immed: true, 68 | latedef: true, 69 | newcap: true, 70 | noarg: true, 71 | sub: true, 72 | undef: true, 73 | unused: true, 74 | boss: true, 75 | eqnull: true, 76 | browser: true, 77 | globalstrict: true, 78 | globals: { 79 | jQuery: true, 80 | angular: false, 81 | Odometer: false 82 | } 83 | }, 84 | gruntfile: { 85 | src: 'Gruntfile.js' 86 | }, 87 | lib_test: { 88 | src: ['lib/**/*.js', 'test/**/*.js'] 89 | } 90 | }, 91 | qunit: { 92 | files: ['test/**/*.html'] 93 | }, 94 | watch: { 95 | gruntfile: { 96 | files: '<%= jshint.gruntfile.src %>', 97 | tasks: ['jshint:gruntfile'] 98 | }, 99 | lib_test: { 100 | files: '<%= jshint.lib_test.src %>', 101 | tasks: ['jshint:lib_test', 'qunit'] 102 | } 103 | }, 104 | cssmin: { 105 | minify: { 106 | expand: true, 107 | cwd: 'lib/', 108 | src: ['*.css', '!*.min.css'], 109 | dest: 'dist/', 110 | ext: '.min.css' 111 | } 112 | }, 113 | 'gh-pages': { 114 | options: { 115 | base: 'examples/dist' 116 | }, 117 | src: '**/*' 118 | } 119 | }); 120 | 121 | // Default task. 122 | grunt.registerTask('default', ['jshint', 'concat', 'uglify', 'cssmin']); 123 | 124 | grunt.registerTask('pages', ['gh-pages']); 125 | 126 | }; 127 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Bahaaldine 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/bahaaldine/angular-csv-import.svg?branch=master)](https://travis-ci.org/bahaaldine/angular-csv-import) 2 | [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 3 | 4 | # Angular CSV Import 5 | 6 | ## Demo page 7 | 8 | http://bahaaldine.github.io/angular-csv-import 9 | 10 | ## Installation 11 | 12 | Install depedencies using bower: 13 | ``` 14 | bower install angular-csv-import 15 | ``` 16 | 17 | Add js libraries to your application: 18 | ```html 19 | ... 20 | 21 | ... 22 | ``` 23 | 24 | Add ngCSVImport module to you application 25 | ```javascript 26 | ... 27 | angular 28 | .module('myAwesomeApp', [ 29 | ... 30 | 'ngCsvImport', 31 | ... 32 | ]) 33 | ... 34 | ``` 35 | 36 | ## Usage 37 | Include the **ng-csv-import** element with its options: 38 | 39 | ```html 40 | 48 | ``` 49 | 50 | - **multiple** 51 | 52 | If `multiple` attribute setted the directive will thow an error due a not implemented yet logic. 53 | 54 | - **material** 55 | 56 | Attribute to tell to the directive to activate the material power! 57 | 58 | - **md-button-class** 59 | 60 | Attribute to personalize the md-button inside the directive 61 | 62 | - **md-svg-icon** 63 | 64 | The icon to show in md-button 65 | 66 | - **csv.content** 67 | 68 | A variable which will contain the content loaded by the file input 69 | 70 | - **csv.header** 71 | 72 | A variable that says whether or not the source CSV file contains headers 73 | 74 | - **csv.headerVisible** 75 | 76 | A variable to toggle header visibility 77 | 78 | - **csv.separator** 79 | 80 | A variable containing the separator used in the CSV file 81 | 82 | - **csv.separatorVisible** 83 | 84 | A variable to toggle separator visibility 85 | 86 | - **csv.encoding** 87 | 88 | A variable to set the CSV file encoding 89 | 90 | - **csv.encodingVisible** 91 | 92 | A variable to toggle encoding visibility 93 | 94 | - **csv.result** 95 | 96 | A variable which will contain the result of the CSV to JSON marshalling. 97 | 98 | - **csv.accept** 99 | 100 | An optional variable to limit what file types are accepted. Ex. ".csv" to only accept csv file types. 101 | 102 | - **csv.acceptSize** 103 | 104 | An optional variable to limit the size of the files that are accepted in bytes. Ex. "1024" to only accept files up to 1kB. 105 | 106 | - **csv.acceptSizeExceedCallback** 107 | 108 | An optional variable to pass in a callback to execute if the user attempted to upload a file larger than csv.acceptSize. Will run instead of parsing. 109 | 110 | - **csv.callback** 111 | 112 | An optional variable to pass in a callback to execute once the file has been parsed. Will run following any successful parsing (ie change file, change separator, etc...). 113 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-csv-import", 3 | "version": "0.0.38", 4 | "main": "dist/angular-csv-import.js", 5 | "license": "MIT", 6 | "authors": [ 7 | "Bahaaldine AZARMI " 8 | ], 9 | "homepage": "https://github.com/cybadave/angular-csv-import", 10 | "description": "angular component let's you import a CSV file", 11 | "keywords": [ 12 | "angular", 13 | "csv", 14 | "import" 15 | ], 16 | "ignore": [ 17 | "source", 18 | "spec", 19 | ".bowerrc", 20 | ".gitignore", 21 | ".jshintignore", 22 | ".jshintrc", 23 | "bower.json", 24 | "gruntfile.js", 25 | "package.json", 26 | "README.md" 27 | ], 28 | "dependencies": { 29 | }, 30 | "devDependencies": { 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /dist/angular-csv-import.js: -------------------------------------------------------------------------------- 1 | /*! angular-csv-import - v0.0.37 - 2017-05-19 2 | * Copyright (c) 2017 ; Licensed */ 3 | 'use strict'; 4 | 5 | var csvImport = angular.module('ngCsvImport', []); 6 | 7 | csvImport.directive('ngCsvImport', function() { 8 | return { 9 | restrict: 'E', 10 | transclude: true, 11 | replace: true, 12 | scope:{ 13 | content:'=?', 14 | header: '=?', 15 | headerVisible: '=?', 16 | separator: '=?', 17 | separatorVisible: '=?', 18 | result: '=?', 19 | encoding: '=?', 20 | encodingVisible: '=?', 21 | accept: '=?', 22 | acceptSize: '=?', 23 | acceptSizeExceedCallback: '=?', 24 | callback: '=?', 25 | mdButtonClass: '@?', 26 | mdInputClass: '@?', 27 | mdButtonTitle: '@?', 28 | mdSvgIcon: '@?', 29 | uploadButtonLabel: '=', 30 | lockImportSameFile:'=?' 31 | }, 32 | template: function(element, attrs) { 33 | var material = angular.isDefined(attrs.material); 34 | var multiple = angular.isDefined(attrs.multiple); 35 | return '
'+ 36 | '
Header
' + 37 | (material ? '
' : 38 | '') + 39 | '
Encoding
{{encoding}}
'+ 40 | '
'+ 41 | '
Seperator
'+ 42 | ''+ 43 | '
'+ 44 | '
' + 45 | '' + 46 | (material ? ' {{mdButtonTitle}}' : '') + 47 | '
'+ 48 | '
'; 49 | }, 50 | link: function(scope, element, attrs) { 51 | scope.separatorVisible = !!scope.separatorVisible; 52 | scope.headerVisible = !!scope.headerVisible; 53 | scope.acceptSize = scope.acceptSize || Number.POSITIVE_INFINITY; 54 | scope.material = angular.isDefined(attrs.material); 55 | scope.multiple = angular.isDefined(attrs.multiple); 56 | if (scope.multiple) { 57 | throw new Error("Multiple attribute is not supported yet."); 58 | } 59 | var input = angular.element(element[0].querySelector('input[type="file"]')); 60 | var inputContainer = angular.element(element[0].querySelector('md-input-container')); 61 | 62 | if (scope.material && input) { 63 | input.removeClass("ng-show"); 64 | input.addClass("ng-hide"); 65 | if (inputContainer) { 66 | var errorSpacer = angular.element(inputContainer[0].querySelector('div.md-errors-spacer')); 67 | if (errorSpacer) { 68 | errorSpacer.remove(); 69 | } 70 | } 71 | scope.onClick = function() { 72 | input.click(); 73 | }; 74 | } 75 | 76 | angular.element(element[0].querySelector('.separator-input')).on('keyup', function(e) { 77 | if ( scope.content != null ) { 78 | var content = { 79 | csv: scope.content, 80 | header: scope.header, 81 | separator: e.target.value, 82 | encoding: scope.encoding 83 | }; 84 | scope.result = csvToJSON(content); 85 | scope.$apply(); 86 | if ( typeof scope.callback === 'function' ) { 87 | if ( scope.callback != null) { 88 | scope.callback(e); 89 | } 90 | } 91 | } 92 | }); 93 | 94 | element.on('change', function(onChangeEvent) { 95 | if (!onChangeEvent.target.files.length){ 96 | return; 97 | } 98 | 99 | if (onChangeEvent.target.files[0].size > scope.acceptSize){ 100 | if ( typeof scope.acceptSizeExceedCallback === 'function' ) { 101 | scope.acceptSizeExceedCallback(onChangeEvent.target.files[0]); 102 | } 103 | return; 104 | } 105 | 106 | scope.filename = onChangeEvent.target.files[0].name; 107 | var reader = new FileReader(); 108 | reader.onload = function(onLoadEvent) { 109 | scope.$apply(function() { 110 | var content = { 111 | csv: onLoadEvent.target.result.replace(/\r\n|\r/g,'\n'), 112 | header: scope.header, 113 | separator: scope.separator 114 | }; 115 | scope.content = content.csv; 116 | scope.result = csvToJSON(content); 117 | scope.result.filename = scope.filename; 118 | scope.$$postDigest(function(){ 119 | if ( typeof scope.callback === 'function' ) { 120 | if ( scope.callback != null) { 121 | scope.callback(onChangeEvent); 122 | } 123 | } 124 | }); 125 | }); 126 | }; 127 | 128 | if ( (onChangeEvent.target.type === "file") && (onChangeEvent.target.files != null || onChangeEvent.srcElement.files != null) ) { 129 | reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0], scope.encoding); 130 | } else { 131 | if ( scope.content != null ) { 132 | var content = { 133 | csv: scope.content, 134 | header: !scope.header, 135 | separator: scope.separator 136 | }; 137 | scope.result = csvToJSON(content); 138 | scope.$$postDigest(function(){ 139 | if ( typeof scope.callback === 'function' ) { 140 | if ( scope.callback != null) { 141 | scope.callback(onChangeEvent); 142 | } 143 | } 144 | }); 145 | } 146 | } 147 | 148 | if(!scope.lockImportSameFile){ 149 | angular.element(document).find('.ng-csv-import.ng-isolate-scope input[type="file"]')[0].value = null; 150 | } 151 | }); 152 | 153 | var csvToJSON = function(content) { 154 | var lines=content.csv.split(new RegExp('\n(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)')); 155 | var result = []; 156 | var start = 0; 157 | var columnCount = lines[0].split(content.separator).length; 158 | 159 | var headers = []; 160 | if (content.header) { 161 | headers=lines[0].split(content.separator); 162 | start = 1; 163 | } 164 | 165 | for (var i=start; i
Header
'+(c?'
':'')+'
Encoding
{{encoding}}
Seperator
'+(c?' {{mdButtonTitle}}':"")+"
"},link:function(a,b,c){if(a.separatorVisible=!!a.separatorVisible,a.headerVisible=!!a.headerVisible,a.acceptSize=a.acceptSize||Number.POSITIVE_INFINITY,a.material=angular.isDefined(c.material),a.multiple=angular.isDefined(c.multiple),a.multiple)throw new Error("Multiple attribute is not supported yet.");var d=angular.element(b[0].querySelector('input[type="file"]')),e=angular.element(b[0].querySelector("md-input-container"));if(a.material&&d){if(d.removeClass("ng-show"),d.addClass("ng-hide"),e){var f=angular.element(e[0].querySelector("div.md-errors-spacer"));f&&f.remove()}a.onClick=function(){d.click()}}angular.element(b[0].querySelector(".separator-input")).on("keyup",function(b){if(null!=a.content){var c={csv:a.content,header:a.header,separator:b.target.value,encoding:a.encoding};a.result=g(c),a.$apply(),"function"==typeof a.callback&&null!=a.callback&&a.callback(b)}}),b.on("change",function(b){if(b.target.files.length){if(b.target.files[0].size>a.acceptSize)return void("function"==typeof a.acceptSizeExceedCallback&&a.acceptSizeExceedCallback(b.target.files[0]));a.filename=b.target.files[0].name;var c=new FileReader;if(c.onload=function(c){a.$apply(function(){var d={csv:c.target.result.replace(/\r\n|\r/g,"\n"),header:a.header,separator:a.separator};a.content=d.csv,a.result=g(d),a.result.filename=a.filename,a.$$postDigest(function(){"function"==typeof a.callback&&null!=a.callback&&a.callback(b)})})},"file"!==b.target.type||null==b.target.files&&null==b.srcElement.files){if(null!=a.content){var d={csv:a.content,header:!a.header,separator:a.separator};a.result=g(d),a.$$postDigest(function(){"function"==typeof a.callback&&null!=a.callback&&a.callback(b)})}}else c.readAsText((b.srcElement||b.target).files[0],a.encoding)}});var g=function(a){var b=a.csv.split(new RegExp('\n(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)')),c=[],d=0,e=b[0].split(a.separator).length,f=[];a.header&&(f=b[0].split(a.separator),d=1);for(var g=d;g/scripts/{,*/}*.js'], 36 | tasks: ['newer:jshint:all'], 37 | options: { 38 | livereload: '<%= connect.options.livereload %>' 39 | } 40 | }, 41 | jsTest: { 42 | files: ['test/spec/{,*/}*.js'], 43 | tasks: ['newer:jshint:test', 'karma'] 44 | }, 45 | styles: { 46 | files: ['<%= yeoman.app %>/styles/{,*/}*.css'], 47 | tasks: ['newer:copy:styles', 'autoprefixer'] 48 | }, 49 | gruntfile: { 50 | files: ['Gruntfile.js'] 51 | }, 52 | livereload: { 53 | options: { 54 | livereload: '<%= connect.options.livereload %>' 55 | }, 56 | files: [ 57 | '<%= yeoman.app %>/{,*/}*.html', 58 | '.tmp/styles/{,*/}*.css', 59 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 60 | ] 61 | } 62 | }, 63 | 64 | // The actual grunt server settings 65 | connect: { 66 | options: { 67 | port: 9000, 68 | // Change this to '0.0.0.0' to access the server from outside. 69 | hostname: 'localhost', 70 | livereload: 35729 71 | }, 72 | livereload: { 73 | options: { 74 | open: true, 75 | base: [ 76 | '.tmp', 77 | '<%= yeoman.app %>' 78 | ] 79 | } 80 | }, 81 | test: { 82 | options: { 83 | port: 9001, 84 | base: [ 85 | '.tmp', 86 | 'test', 87 | '<%= yeoman.app %>' 88 | ] 89 | } 90 | }, 91 | dist: { 92 | options: { 93 | open: true, 94 | base: '<%= yeoman.dist %>' 95 | } 96 | } 97 | }, 98 | 99 | // Make sure code styles are up to par and there are no obvious mistakes 100 | jshint: { 101 | options: { 102 | jshintrc: '.jshintrc', 103 | reporter: require('jshint-stylish') 104 | }, 105 | all: { 106 | src: [ 107 | 'Gruntfile.js', 108 | '<%= yeoman.app %>/scripts/{,*/}*.js' 109 | ] 110 | }, 111 | test: { 112 | options: { 113 | jshintrc: 'test/.jshintrc' 114 | }, 115 | src: ['test/spec/{,*/}*.js'] 116 | } 117 | }, 118 | 119 | // Empties folders to start fresh 120 | clean: { 121 | dist: { 122 | files: [{ 123 | dot: true, 124 | src: [ 125 | '.tmp', 126 | '<%= yeoman.dist %>/{,*/}*', 127 | '!<%= yeoman.dist %>/.git*' 128 | ] 129 | }] 130 | }, 131 | server: '.tmp' 132 | }, 133 | 134 | // Add vendor prefixed styles 135 | autoprefixer: { 136 | options: { 137 | browsers: ['last 1 version'] 138 | }, 139 | dist: { 140 | files: [{ 141 | expand: true, 142 | cwd: '.tmp/styles/', 143 | src: '{,*/}*.css', 144 | dest: '.tmp/styles/' 145 | }] 146 | } 147 | }, 148 | 149 | // Automatically inject Bower components into the app 150 | wiredep: { 151 | app: { 152 | src: ['<%= yeoman.app %>/index.html'], 153 | ignorePath: new RegExp('^<%= yeoman.app %>/') 154 | } 155 | }, 156 | 157 | // Renames files for browser caching purposes 158 | filerev: { 159 | dist: { 160 | src: [ 161 | '<%= yeoman.dist %>/scripts/{,*/}*.js', 162 | '<%= yeoman.dist %>/styles/{,*/}*.css', 163 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 164 | '<%= yeoman.dist %>/styles/fonts/*' 165 | ] 166 | } 167 | }, 168 | 169 | // Reads HTML for usemin blocks to enable smart builds that automatically 170 | // concat, minify and revision files. Creates configurations in memory so 171 | // additional tasks can operate on them 172 | useminPrepare: { 173 | html: '<%= yeoman.app %>/index.html', 174 | options: { 175 | dest: '<%= yeoman.dist %>', 176 | flow: { 177 | html: { 178 | steps: { 179 | js: ['concat', 'uglifyjs'], 180 | css: ['cssmin'] 181 | }, 182 | post: {} 183 | } 184 | } 185 | } 186 | }, 187 | 188 | // Performs rewrites based on filerev and the useminPrepare configuration 189 | usemin: { 190 | html: ['<%= yeoman.dist %>/{,*/}*.html'], 191 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], 192 | options: { 193 | assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist %>/images'] 194 | } 195 | }, 196 | 197 | imagemin: { 198 | dist: { 199 | files: [{ 200 | expand: true, 201 | cwd: '<%= yeoman.app %>/images', 202 | src: '{,*/}*.{png,jpg,jpeg,gif}', 203 | dest: '<%= yeoman.dist %>/images' 204 | }] 205 | } 206 | }, 207 | 208 | svgmin: { 209 | dist: { 210 | files: [{ 211 | expand: true, 212 | cwd: '<%= yeoman.app %>/images', 213 | src: '{,*/}*.svg', 214 | dest: '<%= yeoman.dist %>/images' 215 | }] 216 | } 217 | }, 218 | 219 | htmlmin: { 220 | dist: { 221 | options: { 222 | collapseWhitespace: true, 223 | conservativeCollapse: true, 224 | collapseBooleanAttributes: true, 225 | removeCommentsFromCDATA: true, 226 | removeOptionalTags: true 227 | }, 228 | files: [{ 229 | expand: true, 230 | cwd: '<%= yeoman.dist %>', 231 | src: ['*.html', 'views/{,*/}*.html'], 232 | dest: '<%= yeoman.dist %>' 233 | }] 234 | } 235 | }, 236 | 237 | // ngmin tries to make the code safe for minification automatically by 238 | // using the Angular long form for dependency injection. It doesn't work on 239 | // things like resolve or inject so those have to be done manually. 240 | ngmin: { 241 | dist: { 242 | files: [{ 243 | expand: true, 244 | cwd: '.tmp/concat/scripts', 245 | src: '*.js', 246 | dest: '.tmp/concat/scripts' 247 | }] 248 | } 249 | }, 250 | 251 | // Replace Google CDN references 252 | cdnify: { 253 | dist: { 254 | html: ['<%= yeoman.dist %>/*.html'] 255 | } 256 | }, 257 | 258 | // Copies remaining files to places other tasks can use 259 | copy: { 260 | dist: { 261 | files: [{ 262 | expand: true, 263 | dot: true, 264 | cwd: '<%= yeoman.app %>', 265 | dest: '<%= yeoman.dist %>', 266 | src: [ 267 | '*.{ico,png,txt}', 268 | '.htaccess', 269 | '*.html', 270 | 'views/{,*/}*.html', 271 | 'images/{,*/}*.{webp}', 272 | 'fonts/*' 273 | ] 274 | }, { 275 | expand: true, 276 | cwd: '.tmp/images', 277 | dest: '<%= yeoman.dist %>/images', 278 | src: ['generated/*'] 279 | }, { 280 | expand: true, 281 | dot: true, 282 | cwd: '<%= yeoman.app %>/bower_components/font-awesome/', 283 | dest: '<%= yeoman.dist %>', 284 | src: [ 285 | 'fonts/*', 286 | ] 287 | }] 288 | }, 289 | styles: { 290 | expand: true, 291 | cwd: '<%= yeoman.app %>/styles', 292 | dest: '.tmp/styles/', 293 | src: '{,*/}*.css' 294 | } 295 | }, 296 | 297 | // Run some tasks in parallel to speed up the build process 298 | concurrent: { 299 | server: [ 300 | 'copy:styles' 301 | ], 302 | test: [ 303 | 'copy:styles' 304 | ], 305 | dist: [ 306 | 'copy:styles', 307 | 'imagemin', 308 | 'svgmin' 309 | ] 310 | }, 311 | 312 | // Test settings 313 | karma: { 314 | unit: { 315 | configFile: 'test/karma.conf.js', 316 | singleRun: true 317 | } 318 | } 319 | }); 320 | 321 | 322 | grunt.registerTask('serve', 'Compile then start a connect web server', function (target) { 323 | if (target === 'dist') { 324 | return grunt.task.run(['build', 'connect:dist:keepalive']); 325 | } 326 | 327 | grunt.task.run([ 328 | 'clean:server', 329 | 'wiredep', 330 | 'concurrent:server', 331 | 'autoprefixer', 332 | 'connect:livereload', 333 | 'watch' 334 | ]); 335 | }); 336 | 337 | grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) { 338 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); 339 | grunt.task.run(['serve:' + target]); 340 | }); 341 | 342 | grunt.registerTask('test', [ 343 | 'clean:server', 344 | 'concurrent:test', 345 | 'autoprefixer', 346 | 'connect:test' 347 | ]); 348 | 349 | grunt.registerTask('build', [ 350 | 'clean:dist', 351 | 'wiredep', 352 | 'useminPrepare', 353 | 'concurrent:dist', 354 | 'autoprefixer', 355 | 'concat', 356 | 'ngmin', 357 | 'copy:dist', 358 | 'cdnify', 359 | 'cssmin', 360 | 'uglify', 361 | 'filerev', 362 | 'usemin', 363 | 'htmlmin' 364 | ]); 365 | 366 | grunt.registerTask('default', [ 367 | 'newer:jshint', 368 | 'test', 369 | 'build' 370 | ]); 371 | }; 372 | -------------------------------------------------------------------------------- /examples/app/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /examples/app/.htaccess: -------------------------------------------------------------------------------- 1 | # Apache Configuration File 2 | 3 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access 4 | # to the main server config file (usually called `httpd.conf`), you should add 5 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. 6 | 7 | # ############################################################################## 8 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) # 9 | # ############################################################################## 10 | 11 | # ------------------------------------------------------------------------------ 12 | # | Cross-domain AJAX requests | 13 | # ------------------------------------------------------------------------------ 14 | 15 | # Enable cross-origin AJAX requests. 16 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity 17 | # http://enable-cors.org/ 18 | 19 | # 20 | # Header set Access-Control-Allow-Origin "*" 21 | # 22 | 23 | # ------------------------------------------------------------------------------ 24 | # | CORS-enabled images | 25 | # ------------------------------------------------------------------------------ 26 | 27 | # Send the CORS header for images when browsers request it. 28 | # https://developer.mozilla.org/en/CORS_Enabled_Image 29 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 30 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ 31 | 32 | 33 | 34 | 35 | SetEnvIf Origin ":" IS_CORS 36 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 37 | 38 | 39 | 40 | 41 | # ------------------------------------------------------------------------------ 42 | # | Web fonts access | 43 | # ------------------------------------------------------------------------------ 44 | 45 | # Allow access from all domains for web fonts 46 | 47 | 48 | 49 | Header set Access-Control-Allow-Origin "*" 50 | 51 | 52 | 53 | 54 | # ############################################################################## 55 | # # ERRORS # 56 | # ############################################################################## 57 | 58 | # ------------------------------------------------------------------------------ 59 | # | 404 error prevention for non-existing redirected folders | 60 | # ------------------------------------------------------------------------------ 61 | 62 | # Prevent Apache from returning a 404 error for a rewrite if a directory 63 | # with the same name does not exist. 64 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews 65 | # http://www.webmasterworld.com/apache/3808792.htm 66 | 67 | Options -MultiViews 68 | 69 | # ------------------------------------------------------------------------------ 70 | # | Custom error messages / pages | 71 | # ------------------------------------------------------------------------------ 72 | 73 | # You can customize what Apache returns to the client in case of an error (see 74 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.: 75 | 76 | ErrorDocument 404 /404.html 77 | 78 | 79 | # ############################################################################## 80 | # # INTERNET EXPLORER # 81 | # ############################################################################## 82 | 83 | # ------------------------------------------------------------------------------ 84 | # | Better website experience | 85 | # ------------------------------------------------------------------------------ 86 | 87 | # Force IE to render pages in the highest available mode in the various 88 | # cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf. 89 | 90 | 91 | Header set X-UA-Compatible "IE=edge" 92 | # `mod_headers` can't match based on the content-type, however, we only 93 | # want to send this header for HTML pages and not for the other resources 94 | 95 | Header unset X-UA-Compatible 96 | 97 | 98 | 99 | # ------------------------------------------------------------------------------ 100 | # | Cookie setting from iframes | 101 | # ------------------------------------------------------------------------------ 102 | 103 | # Allow cookies to be set from iframes in IE. 104 | 105 | # 106 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 107 | # 108 | 109 | # ------------------------------------------------------------------------------ 110 | # | Screen flicker | 111 | # ------------------------------------------------------------------------------ 112 | 113 | # Stop screen flicker in IE on CSS rollovers (this only works in 114 | # combination with the `ExpiresByType` directives for images from below). 115 | 116 | # BrowserMatch "MSIE" brokenvary=1 117 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 118 | # BrowserMatch "Opera" !brokenvary 119 | # SetEnvIf brokenvary 1 force-no-vary 120 | 121 | 122 | # ############################################################################## 123 | # # MIME TYPES AND ENCODING # 124 | # ############################################################################## 125 | 126 | # ------------------------------------------------------------------------------ 127 | # | Proper MIME types for all files | 128 | # ------------------------------------------------------------------------------ 129 | 130 | 131 | 132 | # Audio 133 | AddType audio/mp4 m4a f4a f4b 134 | AddType audio/ogg oga ogg 135 | 136 | # JavaScript 137 | # Normalize to standard type (it's sniffed in IE anyways): 138 | # http://tools.ietf.org/html/rfc4329#section-7.2 139 | AddType application/javascript js jsonp 140 | AddType application/json json 141 | 142 | # Video 143 | AddType video/mp4 mp4 m4v f4v f4p 144 | AddType video/ogg ogv 145 | AddType video/webm webm 146 | AddType video/x-flv flv 147 | 148 | # Web fonts 149 | AddType application/font-woff woff 150 | AddType application/vnd.ms-fontobject eot 151 | 152 | # Browsers usually ignore the font MIME types and sniff the content, 153 | # however, Chrome shows a warning if other MIME types are used for the 154 | # following fonts. 155 | AddType application/x-font-ttf ttc ttf 156 | AddType font/opentype otf 157 | 158 | # Make SVGZ fonts work on iPad: 159 | # https://twitter.com/FontSquirrel/status/14855840545 160 | AddType image/svg+xml svg svgz 161 | AddEncoding gzip svgz 162 | 163 | # Other 164 | AddType application/octet-stream safariextz 165 | AddType application/x-chrome-extension crx 166 | AddType application/x-opera-extension oex 167 | AddType application/x-shockwave-flash swf 168 | AddType application/x-web-app-manifest+json webapp 169 | AddType application/x-xpinstall xpi 170 | AddType application/xml atom rdf rss xml 171 | AddType image/webp webp 172 | AddType image/x-icon ico 173 | AddType text/cache-manifest appcache manifest 174 | AddType text/vtt vtt 175 | AddType text/x-component htc 176 | AddType text/x-vcard vcf 177 | 178 | 179 | 180 | # ------------------------------------------------------------------------------ 181 | # | UTF-8 encoding | 182 | # ------------------------------------------------------------------------------ 183 | 184 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 185 | AddDefaultCharset utf-8 186 | 187 | # Force UTF-8 for certain file formats. 188 | 189 | AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml 190 | 191 | 192 | 193 | # ############################################################################## 194 | # # URL REWRITES # 195 | # ############################################################################## 196 | 197 | # ------------------------------------------------------------------------------ 198 | # | Rewrite engine | 199 | # ------------------------------------------------------------------------------ 200 | 201 | # Turning on the rewrite engine and enabling the `FollowSymLinks` option is 202 | # necessary for the following directives to work. 203 | 204 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 205 | # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the 206 | # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 207 | 208 | # Also, some cloud hosting services require `RewriteBase` to be set: 209 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 210 | 211 | 212 | Options +FollowSymlinks 213 | # Options +SymLinksIfOwnerMatch 214 | RewriteEngine On 215 | # RewriteBase / 216 | 217 | 218 | # ------------------------------------------------------------------------------ 219 | # | Suppressing / Forcing the "www." at the beginning of URLs | 220 | # ------------------------------------------------------------------------------ 221 | 222 | # The same content should never be available under two different URLs especially 223 | # not with and without "www." at the beginning. This can cause SEO problems 224 | # (duplicate content), therefore, you should choose one of the alternatives and 225 | # redirect the other one. 226 | 227 | # By default option 1 (no "www.") is activated: 228 | # http://no-www.org/faq.php?q=class_b 229 | 230 | # If you'd prefer to use option 2, just comment out all the lines from option 1 231 | # and uncomment the ones from option 2. 232 | 233 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 234 | 235 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 236 | 237 | # Option 1: rewrite www.example.com → example.com 238 | 239 | 240 | RewriteCond %{HTTPS} !=on 241 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 242 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 243 | 244 | 245 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 246 | 247 | # Option 2: rewrite example.com → www.example.com 248 | 249 | # Be aware that the following might not be a good idea if you use "real" 250 | # subdomains for certain parts of your website. 251 | 252 | # 253 | # RewriteCond %{HTTPS} !=on 254 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC] 255 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 256 | # 257 | 258 | 259 | # ############################################################################## 260 | # # SECURITY # 261 | # ############################################################################## 262 | 263 | # ------------------------------------------------------------------------------ 264 | # | Content Security Policy (CSP) | 265 | # ------------------------------------------------------------------------------ 266 | 267 | # You can mitigate the risk of cross-site scripting and other content-injection 268 | # attacks by setting a Content Security Policy which whitelists trusted sources 269 | # of content for your site. 270 | 271 | # The example header below allows ONLY scripts that are loaded from the current 272 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 273 | # work as-is for your site! 274 | 275 | # To get all the details you'll need to craft a reasonable policy for your site, 276 | # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or 277 | # see the specification: http://w3.org/TR/CSP). 278 | 279 | # 280 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 281 | # 282 | # Header unset Content-Security-Policy 283 | # 284 | # 285 | 286 | # ------------------------------------------------------------------------------ 287 | # | File access | 288 | # ------------------------------------------------------------------------------ 289 | 290 | # Block access to directories without a default document. 291 | # Usually you should leave this uncommented because you shouldn't allow anyone 292 | # to surf through every directory on your server (which may includes rather 293 | # private places like the CMS's directories). 294 | 295 | 296 | Options -Indexes 297 | 298 | 299 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 300 | 301 | # Block access to hidden files and directories. 302 | # This includes directories used by version control systems such as Git and SVN. 303 | 304 | 305 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 306 | RewriteCond %{SCRIPT_FILENAME} -f 307 | RewriteRule "(^|/)\." - [F] 308 | 309 | 310 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 311 | 312 | # Block access to backup and source files. 313 | # These files may be left by some text editors and can pose a great security 314 | # danger when anyone has access to them. 315 | 316 | 317 | Order allow,deny 318 | Deny from all 319 | Satisfy All 320 | 321 | 322 | # ------------------------------------------------------------------------------ 323 | # | Secure Sockets Layer (SSL) | 324 | # ------------------------------------------------------------------------------ 325 | 326 | # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: 327 | # prevent `https://www.example.com` when your certificate only allows 328 | # `https://secure.example.com`. 329 | 330 | # 331 | # RewriteCond %{SERVER_PORT} !^443 332 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 333 | # 334 | 335 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 336 | 337 | # Force client-side SSL redirection. 338 | 339 | # If a user types "example.com" in his browser, the above rule will redirect him 340 | # to the secure version of the site. That still leaves a window of opportunity 341 | # (the initial HTTP connection) for an attacker to downgrade or redirect the 342 | # request. The following header ensures that browser will ONLY connect to your 343 | # server via HTTPS, regardless of what the users type in the address bar. 344 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 345 | 346 | # 347 | # Header set Strict-Transport-Security max-age=16070400; 348 | # 349 | 350 | # ------------------------------------------------------------------------------ 351 | # | Server software information | 352 | # ------------------------------------------------------------------------------ 353 | 354 | # Avoid displaying the exact Apache version number, the description of the 355 | # generic OS-type and the information about Apache's compiled-in modules. 356 | 357 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 358 | 359 | # ServerTokens Prod 360 | 361 | 362 | # ############################################################################## 363 | # # WEB PERFORMANCE # 364 | # ############################################################################## 365 | 366 | # ------------------------------------------------------------------------------ 367 | # | Compression | 368 | # ------------------------------------------------------------------------------ 369 | 370 | 371 | 372 | # Force compression for mangled headers. 373 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 374 | 375 | 376 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 377 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 378 | 379 | 380 | 381 | # Compress all output labeled with one of the following MIME-types 382 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 383 | # and can remove the `` and `` lines 384 | # as `AddOutputFilterByType` is still in the core directives). 385 | 386 | AddOutputFilterByType DEFLATE application/atom+xml \ 387 | application/javascript \ 388 | application/json \ 389 | application/rss+xml \ 390 | application/vnd.ms-fontobject \ 391 | application/x-font-ttf \ 392 | application/x-web-app-manifest+json \ 393 | application/xhtml+xml \ 394 | application/xml \ 395 | font/opentype \ 396 | image/svg+xml \ 397 | image/x-icon \ 398 | text/css \ 399 | text/html \ 400 | text/plain \ 401 | text/x-component \ 402 | text/xml 403 | 404 | 405 | 406 | 407 | # ------------------------------------------------------------------------------ 408 | # | Content transformations | 409 | # ------------------------------------------------------------------------------ 410 | 411 | # Prevent some of the mobile network providers from modifying the content of 412 | # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 413 | 414 | # 415 | # Header set Cache-Control "no-transform" 416 | # 417 | 418 | # ------------------------------------------------------------------------------ 419 | # | ETag removal | 420 | # ------------------------------------------------------------------------------ 421 | 422 | # Since we're sending far-future expires headers (see below), ETags can 423 | # be removed: http://developer.yahoo.com/performance/rules.html#etags. 424 | 425 | # `FileETag None` is not enough for every server. 426 | 427 | Header unset ETag 428 | 429 | 430 | FileETag None 431 | 432 | # ------------------------------------------------------------------------------ 433 | # | Expires headers (for better cache control) | 434 | # ------------------------------------------------------------------------------ 435 | 436 | # The following expires headers are set pretty far in the future. If you don't 437 | # control versioning with filename-based cache busting, consider lowering the 438 | # cache time for resources like CSS and JS to something like 1 week. 439 | 440 | 441 | 442 | ExpiresActive on 443 | ExpiresDefault "access plus 1 month" 444 | 445 | # CSS 446 | ExpiresByType text/css "access plus 1 year" 447 | 448 | # Data interchange 449 | ExpiresByType application/json "access plus 0 seconds" 450 | ExpiresByType application/xml "access plus 0 seconds" 451 | ExpiresByType text/xml "access plus 0 seconds" 452 | 453 | # Favicon (cannot be renamed!) 454 | ExpiresByType image/x-icon "access plus 1 week" 455 | 456 | # HTML components (HTCs) 457 | ExpiresByType text/x-component "access plus 1 month" 458 | 459 | # HTML 460 | ExpiresByType text/html "access plus 0 seconds" 461 | 462 | # JavaScript 463 | ExpiresByType application/javascript "access plus 1 year" 464 | 465 | # Manifest files 466 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 467 | ExpiresByType text/cache-manifest "access plus 0 seconds" 468 | 469 | # Media 470 | ExpiresByType audio/ogg "access plus 1 month" 471 | ExpiresByType image/gif "access plus 1 month" 472 | ExpiresByType image/jpeg "access plus 1 month" 473 | ExpiresByType image/png "access plus 1 month" 474 | ExpiresByType video/mp4 "access plus 1 month" 475 | ExpiresByType video/ogg "access plus 1 month" 476 | ExpiresByType video/webm "access plus 1 month" 477 | 478 | # Web feeds 479 | ExpiresByType application/atom+xml "access plus 1 hour" 480 | ExpiresByType application/rss+xml "access plus 1 hour" 481 | 482 | # Web fonts 483 | ExpiresByType application/font-woff "access plus 1 month" 484 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 485 | ExpiresByType application/x-font-ttf "access plus 1 month" 486 | ExpiresByType font/opentype "access plus 1 month" 487 | ExpiresByType image/svg+xml "access plus 1 month" 488 | 489 | 490 | 491 | # ------------------------------------------------------------------------------ 492 | # | Filename-based cache busting | 493 | # ------------------------------------------------------------------------------ 494 | 495 | # If you're not using a build process to manage your filename version revving, 496 | # you might want to consider enabling the following directives to route all 497 | # requests such as `/css/style.12345.css` to `/css/style.css`. 498 | 499 | # To understand why this is important and a better idea than `*.css?v231`, read: 500 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 501 | 502 | # 503 | # RewriteCond %{REQUEST_FILENAME} !-f 504 | # RewriteCond %{REQUEST_FILENAME} !-d 505 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] 506 | # 507 | 508 | # ------------------------------------------------------------------------------ 509 | # | File concatenation | 510 | # ------------------------------------------------------------------------------ 511 | 512 | # Allow concatenation from within specific CSS and JS files, e.g.: 513 | # Inside of `script.combined.js` you could have 514 | # 515 | # 516 | # and they would be included into this single file. 517 | 518 | # 519 | # 520 | # Options +Includes 521 | # AddOutputFilterByType INCLUDES application/javascript application/json 522 | # SetOutputFilter INCLUDES 523 | # 524 | # 525 | # Options +Includes 526 | # AddOutputFilterByType INCLUDES text/css 527 | # SetOutputFilter INCLUDES 528 | # 529 | # 530 | 531 | # ------------------------------------------------------------------------------ 532 | # | Persistent connections | 533 | # ------------------------------------------------------------------------------ 534 | 535 | # Allow multiple requests to be sent over the same TCP connection: 536 | # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. 537 | 538 | # Enable if you serve a lot of static content but, be aware of the 539 | # possible disadvantages! 540 | 541 | # 542 | # Header set Connection Keep-Alive 543 | # 544 | -------------------------------------------------------------------------------- /examples/app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 |
    148 |
  • a mistyped address
  • 149 |
  • an out-of-date link
  • 150 |
151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /examples/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahaaldine/angular-csv-import/923f17da1dcbc19d40d52a2daa1c8843b1fe6f22/examples/app/favicon.ico -------------------------------------------------------------------------------- /examples/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular CSV Import 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 |
34 |
35 |
36 | 37 | 38 | 39 | 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /examples/app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /examples/app/scripts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc overview 5 | * @name examplesApp 6 | * @description 7 | * # examplesApp 8 | * 9 | * Main module of the application. 10 | */ 11 | angular 12 | .module('examplesApp', [ 13 | 'ngResource', 14 | 'ngRoute', 15 | 'ngCsvImport', 16 | 'hljs', 17 | 'ngMaterial' 18 | ]) 19 | .config(function ($routeProvider) { 20 | $routeProvider 21 | .when('/', { 22 | templateUrl: 'views/main.html', 23 | controller: 'MainCtrl' 24 | }) 25 | .when('/about', { 26 | templateUrl: 'views/about.html', 27 | controller: 'AboutCtrl' 28 | }) 29 | .otherwise({ 30 | redirectTo: '/' 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /examples/app/scripts/controllers/about.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name examplesApp.controller:AboutCtrl 6 | * @description 7 | * # AboutCtrl 8 | * Controller of the examplesApp 9 | */ 10 | angular.module('examplesApp') 11 | .controller('AboutCtrl', function ($scope) { 12 | $scope.awesomeThings = [ 13 | 'HTML5 Boilerplate', 14 | 'AngularJS', 15 | 'Karma' 16 | ]; 17 | }); 18 | -------------------------------------------------------------------------------- /examples/app/scripts/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('examplesApp') 4 | .controller('MainCtrl', ['$scope', '$parse', function ($scope, $parse) { 5 | $scope.Math = window.Math; 6 | $scope.csv = { 7 | content: null, 8 | header: true, 9 | headerVisible: true, 10 | separator: ',', 11 | separatorVisible: true, 12 | result: null, 13 | encoding: 'ISO-8859-1', 14 | encodingVisible: true, 15 | uploadButtonLabel: "upload a csv file", 16 | progressCallback: function(progress) { 17 | $scope.$apply( function() { 18 | $scope.progress = progress; 19 | }); 20 | }, 21 | streamingCallback: function(stream) { 22 | if ( typeof stream != "undefined" ) { 23 | $scope.$apply( function() { 24 | $scope.preview = stream[Math.floor(Math.random()*stream.length)]; 25 | }); 26 | } 27 | }, 28 | streamingErrorCallback: function(streamError) { 29 | console.log(streamError); 30 | } 31 | }; 32 | 33 | var _lastGoodResult = ''; 34 | $scope.toPrettyJSON = function (json, tabWidth) { 35 | var objStr = JSON.stringify(json); 36 | var obj = null; 37 | try { 38 | obj = $parse(objStr)({}); 39 | } catch(e){ 40 | // eat $parse error 41 | return _lastGoodResult; 42 | } 43 | 44 | var result = JSON.stringify(obj, null, Number(tabWidth)); 45 | _lastGoodResult = result; 46 | 47 | return result; 48 | }; 49 | }]); 50 | -------------------------------------------------------------------------------- /examples/app/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 20px; 3 | padding-bottom: 20px; 4 | background: #2c3e50; 5 | } 6 | 7 | div.container { 8 | width: 80%; 9 | margin: 0 auto; 10 | text-align: center; 11 | } 12 | 13 | div.block.row { 14 | width: 100%; 15 | margin: 10px 0px; 16 | } 17 | 18 | div.block.row > div { 19 | display: inline-block; 20 | vertical-align: middle; 21 | } 22 | 23 | div.block.row > div.title { 24 | width: 30%; 25 | color: white; 26 | } 27 | 28 | div.import>div>div.label { 29 | display: inline-block; 30 | width: 30%; 31 | text-align: left; 32 | color: white; 33 | font-family: 'Verdana'; 34 | font-size: 14px; 35 | } 36 | 37 | div.import > div { 38 | margin: 15px 0px; 39 | } 40 | 41 | div.import > div > span { 42 | color: white; 43 | } 44 | 45 | div.import > div> span > input[type="text"] { 46 | font-size: 18px; 47 | color: #d6492f; 48 | font-weight: bold; 49 | border-radius: none; 50 | outline: none; 51 | } 52 | 53 | div.import>div>div>input[type="file"] { 54 | color: transparent; 55 | padding: 0; 56 | } 57 | 58 | div.import>div>div>input[type="file"]::-webkit-file-upload-button { 59 | visibility: hidden; 60 | } 61 | 62 | div.import>div>div>input[type="file"]::before { 63 | content: attr(upload-button-label); 64 | display: inline-block; 65 | background-image: linear-gradient(to top, #f9f9f9 0px, #f9f9f9 50%, #e3e3e3 50%, #e3e3e3 100% ); 66 | color: #444; 67 | border: 1px solid #999; 68 | border-radius: 3px; 69 | padding: 5px 8px; 70 | outline: none; 71 | white-space: nowrap; 72 | -webkit-user-select: none; 73 | cursor: pointer; 74 | text-shadow: 1px 1px #fff; 75 | font-weight: 700; 76 | font-size: 14px; 77 | } 78 | div.import>div>div>input[type="file"]:hover::before { 79 | border-color: black; 80 | } 81 | div.import>div>div>input[type="file"]:active::before { 82 | background: -webkit-linear-gradient(top, #e3e3e3, #f9f9f9); 83 | } 84 | 85 | div.block { 86 | display: inline-block; 87 | vertical-align: middle; 88 | text-align: left; 89 | } 90 | 91 | div.block.left { 92 | } 93 | 94 | div.block>div.content { 95 | border: 5px dashed #d6492f; 96 | background: none; 97 | padding: 0px; 98 | border-radius: 3px; 99 | } 100 | 101 | div.block>div.content>pre { 102 | font-size: 15px; 103 | font-family: 'Courier'; 104 | background: #F0F0F0; 105 | padding: 10px; 106 | margin: 0; 107 | } 108 | 109 | .ng-csv-progress { 110 | color: white; 111 | } 112 | 113 | footer { 114 | } 115 | 116 | footer>div { 117 | color: white; 118 | bottom: 40px; 119 | display: inline-block; 120 | margin: 0px 50px; 121 | } 122 | 123 | footer>div a { 124 | color: white; 125 | text-decoration: none; 126 | font-size: 18px; 127 | } 128 | 129 | footer>div a:hover { 130 | text-decoration: underline; 131 | vertical-align: bottom; 132 | } 133 | 134 | footer>div.twitter { 135 | left: 40px; 136 | } 137 | 138 | footer>div.twitter>div { 139 | display: inline-block; 140 | vertical-align: middle; 141 | } 142 | 143 | footer>div.twitter>div.avatar { 144 | margin: 0px 5px 0px 0px; 145 | background: url("https://avatars1.githubusercontent.com/u/820299?v=3&s=460"); 146 | background-size: contain; 147 | border: solid 3px white; 148 | width: 40px; 149 | height: 40px; 150 | border-radius: 100px; 151 | } 152 | 153 | footer>div.github { 154 | right: 40px; 155 | } 156 | 157 | footer>div.github>div { 158 | display: inline-block; 159 | vertical-align: middle; 160 | } 161 | 162 | footer>div.github>div.icon { 163 | font-size: 35px; 164 | margin: 0px 5px 0px 0px; 165 | } 166 | 167 | -------------------------------------------------------------------------------- /examples/app/views/main.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Select your CSV file:

4 |
5 | 19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /examples/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular": "1.2.16", 6 | "json3": "~3.3.1", 7 | "es5-shim": "~3.1.0", 8 | "angular-resource": "1.2.16", 9 | "angular-route": "1.2.16", 10 | "angular-csv-import": "~0.0.1", 11 | "angular-highlightjs": "~0.3.0", 12 | "bootstrap": "~3.2.0", 13 | "font-awesome": "~4.1.0", 14 | "angular-material": "~1.1.1" 15 | }, 16 | "devDependencies": { 17 | "angular-mocks": "1.2.16", 18 | "angular-scenario": "1.2.16" 19 | }, 20 | "appPath": "app", 21 | "resolutions": { 22 | "angular": "1.5.8" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "examples", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular-material": "^1.1.1" 6 | }, 7 | "devDependencies": { 8 | "grunt": "^0.4.1", 9 | "grunt-autoprefixer": "^0.7.3", 10 | "grunt-concurrent": "^0.5.0", 11 | "grunt-contrib-clean": "^0.5.0", 12 | "grunt-contrib-concat": "^0.4.0", 13 | "grunt-contrib-connect": "^0.7.1", 14 | "grunt-contrib-copy": "^0.5.0", 15 | "grunt-contrib-cssmin": "^0.9.0", 16 | "grunt-contrib-htmlmin": "^0.3.0", 17 | "grunt-contrib-imagemin": "^0.7.0", 18 | "grunt-contrib-jshint": "^0.10.0", 19 | "grunt-contrib-uglify": "^0.4.0", 20 | "grunt-contrib-watch": "^0.6.1", 21 | "grunt-filerev": "^0.2.1", 22 | "grunt-google-cdn": "^0.4.0", 23 | "grunt-newer": "^0.7.0", 24 | "grunt-ngmin": "^0.0.3", 25 | "grunt-svgmin": "^0.4.0", 26 | "grunt-usemin": "^2.1.1", 27 | "grunt-wiredep": "^1.7.0", 28 | "jshint-stylish": "^0.2.0", 29 | "load-grunt-tasks": "^0.4.0", 30 | "time-grunt": "^0.3.1" 31 | }, 32 | "engines": { 33 | "node": ">=0.10.0" 34 | }, 35 | "scripts": { 36 | "test": "grunt test" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/source/source.csv: -------------------------------------------------------------------------------- 1 | column1;column2;column3;column4;column5;column6;column7;column8 2 | row11;row21;row31;row41;row51;row61;row71;row81 3 | row12;row22;row32;row42;row52;row62;row72;row82 4 | row13;row23;row33;row43;row53;row63;row73;row83 5 | row14;row24;row34;row44;row54;row64;row74;row84 6 | row15;row25;row35;row45;row55;row65;row75;row85 7 | row16;row26;row36;row46;row56;row66;row76;row86 8 | row17;row27;row37;row47;row57;row67;row77;row87 9 | row18;row28;row38;row48;row58;row68;row78;row88 10 | row19;row29;row39;row49;row59;row69;row79;row89 11 | row20;row30;row40;row50;row60;row70;row80;row90 12 | row21;row31;row41;row51;row61;row71;row81;row91 13 | row22;row32;row42;row52;row62;row72;row82;row92 14 | row23;row33;row43;row53;row63;row73;row83;row93 15 | row24;row34;row44;row54;row64;row74;row84;row94 16 | row25;row35;row45;row55;row65;row75;row85;row95 17 | row26;row36;row46;row56;row66;row76;row86;row96 18 | row27;row37;row47;row57;row67;row77;row87;row97 19 | row28;row38;row48;row58;row68;row78;row88;row98 20 | row29;row39;row49;row59;row69;row79;row89;row99 21 | row30;row40;row50;row60;row70;row80;row90;row100 22 | row31;row41;row51;row61;row71;row81;row91;row101 23 | row32;row42;row52;row62;row72;row82;row92;row102 24 | row33;row43;row53;row63;row73;row83;row93;row103 25 | row34;row44;row54;row64;row74;row84;row94;row104 26 | row35;row45;row55;row65;row75;row85;row95;row105 27 | row36;row46;row56;row66;row76;row86;row96;row106 28 | row37;row47;row57;row67;row77;row87;row97;row107 29 | row38;row48;row58;row68;row78;row88;row98;row108 30 | row39;row49;row59;row69;row79;row89;row99;row109 31 | row40;row50;row60;row70;row80;row90;row100;row110 32 | row41;row51;row61;row71;row81;row91;row101;row111 33 | row42;row52;row62;row72;row82;row92;row102;row112 34 | row43;row53;row63;row73;row83;row93;row103;row113 35 | row44;row54;row64;row74;row84;row94;row104;row114 36 | row45;row55;row65;row75;row85;row95;row105;row115 37 | row46;row56;row66;row76;row86;row96;row106;row116 38 | row47;row57;row67;row77;row87;row97;row107;row117 39 | row48;row58;row68;row78;row88;row98;row108;row118 40 | row49;row59;row69;row79;row89;row99;row109;row119 41 | row50;row60;row70;row80;row90;row100;row110;row120 42 | row51;row61;row71;row81;row91;row101;row111;row121 43 | row52;row62;row72;row82;row92;row102;row112;row122 44 | row53;row63;row73;row83;row93;row103;row113;row123 45 | row54;row64;row74;row84;row94;row104;row114;row124 46 | row55;row65;row75;row85;row95;row105;row115;row125 47 | row56;row66;row76;row86;row96;row106;row116;row126 48 | row57;row67;row77;row87;row97;row107;row117;row127 49 | row58;row68;row78;row88;row98;row108;row118;row128 50 | row59;row69;row79;row89;row99;row109;row119;row129 51 | row60;row70;row80;row90;row100;row110;row120;row130 52 | row61;row71;row81;row91;row101;row111;row121;row131 53 | row62;row72;row82;row92;row102;row112;row122;row132 54 | row63;row73;row83;row93;row103;row113;row123;row133 55 | row64;row74;row84;row94;row104;row114;row124;row134 56 | row65;row75;row85;row95;row105;row115;row125;row135 57 | row66;row76;row86;row96;row106;row116;row126;row136 58 | row67;row77;row87;row97;row107;row117;row127;row137 59 | row68;row78;row88;row98;row108;row118;row128;row138 60 | row69;row79;row89;row99;row109;row119;row129;row139 61 | row70;row80;row90;row100;row110;row120;row130;row140 62 | row71;row81;row91;row101;row111;row121;row131;row141 63 | row72;row82;row92;row102;row112;row122;row132;row142 64 | row73;row83;row93;row103;row113;row123;row133;row143 65 | row74;row84;row94;row104;row114;row124;row134;row144 66 | row75;row85;row95;row105;row115;row125;row135;row145 67 | row76;row86;row96;row106;row116;row126;row136;row146 68 | row77;row87;row97;row107;row117;row127;row137;row147 69 | row78;row88;row98;row108;row118;row128;row138;row148 70 | row79;row89;row99;row109;row119;row129;row139;row149 71 | row80;row90;row100;row110;row120;row130;row140;row150 72 | row81;row91;row101;row111;row121;row131;row141;row151 73 | row82;row92;row102;row112;row122;row132;row142;row152 74 | row83;row93;row103;row113;row123;row133;row143;row153 75 | row84;row94;row104;row114;row124;row134;row144;row154 -------------------------------------------------------------------------------- /examples/source/source_es.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahaaldine/angular-csv-import/923f17da1dcbc19d40d52a2daa1c8843b1fe6f22/examples/source/source_es.csv -------------------------------------------------------------------------------- /examples/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "globals": { 22 | "after": false, 23 | "afterEach": false, 24 | "angular": false, 25 | "before": false, 26 | "beforeEach": false, 27 | "browser": false, 28 | "describe": false, 29 | "expect": false, 30 | "inject": false, 31 | "it": false, 32 | "jasmine": false, 33 | "spyOn": false 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /examples/test/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // http://karma-runner.github.io/0.12/config/configuration-file.html 3 | // Generated on 2014-07-10 using 4 | // generator-karma 0.8.2 5 | 6 | module.exports = function(config) { 7 | config.set({ 8 | // enable / disable watching file and executing tests whenever any file changes 9 | autoWatch: true, 10 | 11 | // base path, that will be used to resolve files and exclude 12 | basePath: '../', 13 | 14 | // testing framework to use (jasmine/mocha/qunit/...) 15 | frameworks: ['jasmine'], 16 | 17 | // list of files / patterns to load in the browser 18 | files: [ 19 | 'app/bower_components/angular/angular.js', 20 | 'app/bower_components/angular-mocks/angular-mocks.js', 21 | 'app/bower_components/angular-resource/angular-resource.js', 22 | 'app/bower_components/angular-route/angular-route.js', 23 | 'app/scripts/**/*.js', 24 | 'test/mock/**/*.js', 25 | 'test/spec/**/*.js' 26 | ], 27 | 28 | // list of files / patterns to exclude 29 | exclude: [], 30 | 31 | // web server port 32 | port: 8080, 33 | 34 | // Start these browsers, currently available: 35 | // - Chrome 36 | // - ChromeCanary 37 | // - Firefox 38 | // - Opera 39 | // - Safari (only Mac) 40 | // - PhantomJS 41 | // - IE (only Windows) 42 | browsers: [ 43 | 'PhantomJS' 44 | ], 45 | 46 | // Which plugins to enable 47 | plugins: [ 48 | 'karma-phantomjs-launcher', 49 | 'karma-jasmine' 50 | ], 51 | 52 | // Continuous Integration mode 53 | // if true, it capture browsers, run tests and exit 54 | singleRun: false, 55 | 56 | colors: true, 57 | 58 | // level of logging 59 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 60 | logLevel: config.LOG_INFO, 61 | 62 | // Uncomment the following lines if you are using grunt's server to run the tests 63 | // proxies: { 64 | // '/': 'http://localhost:9000/' 65 | // }, 66 | // URL root prevent conflicts with the site root 67 | // urlRoot: '_karma_' 68 | }); 69 | }; 70 | -------------------------------------------------------------------------------- /examples/test/spec/controllers/about.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: AboutCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('examplesApp')); 7 | 8 | var AboutCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | AboutCtrl = $controller('AboutCtrl', { 15 | $scope: scope 16 | }); 17 | })); 18 | 19 | it('should attach a list of awesomeThings to the scope', function () { 20 | expect(scope.awesomeThings.length).toBe(3); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /examples/test/spec/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: MainCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('examplesApp')); 7 | 8 | var MainCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | MainCtrl = $controller('MainCtrl', { 15 | $scope: scope 16 | }); 17 | })); 18 | 19 | it('should attach a list of awesomeThings to the scope', function () { 20 | expect(scope.awesomeThings.length).toBe(3); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bahaaldine/angular-csv-import/923f17da1dcbc19d40d52a2daa1c8843b1fe6f22/lib/.DS_Store -------------------------------------------------------------------------------- /lib/angular-csv-import.css: -------------------------------------------------------------------------------- 1 | ng-csv-import, .ng-csv-import { 2 | display: inline-block; 3 | position: relative; 4 | padding: 2px; 5 | margin: 0; 6 | vertical-align: middle; 7 | } -------------------------------------------------------------------------------- /lib/angular-csv-import.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var csvImport = angular.module('ngCsvImport', []); 4 | 5 | csvImport.directive('ngCsvImport', function() { 6 | return { 7 | restrict: 'E', 8 | transclude: true, 9 | replace: true, 10 | scope:{ 11 | content:'=?', 12 | header: '=?', 13 | headerVisible: '=?', 14 | separator: '=?', 15 | separatorVisible: '=?', 16 | result: '=?', 17 | encoding: '=?', 18 | encodingVisible: '=?', 19 | accept: '=?', 20 | acceptSize: '=?', 21 | acceptSizeExceedCallback: '=?', 22 | callback: '=?', 23 | mdButtonClass: '@?', 24 | mdInputClass: '@?', 25 | mdButtonTitle: '@?', 26 | mdSvgIcon: '@?', 27 | uploadButtonLabel: '=' 28 | }, 29 | template: function(element, attrs) { 30 | var material = angular.isDefined(attrs.material); 31 | var multiple = angular.isDefined(attrs.multiple); 32 | return '
'+ 33 | '
Header
' + 34 | (material ? '
' : 35 | '') + 36 | '
Encoding
{{encoding}}
'+ 37 | '
'+ 38 | '
Seperator
'+ 39 | ''+ 40 | '
'+ 41 | '
' + 42 | '' + 43 | (material ? ' {{mdButtonTitle}}' : '') + 44 | '
'+ 45 | '
'; 46 | }, 47 | link: function(scope, element, attrs) { 48 | scope.separatorVisible = !!scope.separatorVisible; 49 | scope.headerVisible = !!scope.headerVisible; 50 | scope.acceptSize = scope.acceptSize || Number.POSITIVE_INFINITY; 51 | scope.material = angular.isDefined(attrs.material); 52 | scope.multiple = angular.isDefined(attrs.multiple); 53 | if (scope.multiple) { 54 | throw new Error("Multiple attribute is not supported yet."); 55 | } 56 | var input = angular.element(element[0].querySelector('input[type="file"]')); 57 | var inputContainer = angular.element(element[0].querySelector('md-input-container')); 58 | 59 | if (scope.material && input) { 60 | input.removeClass("ng-show"); 61 | input.addClass("ng-hide"); 62 | if (inputContainer) { 63 | var errorSpacer = angular.element(inputContainer[0].querySelector('div.md-errors-spacer')); 64 | if (errorSpacer) { 65 | errorSpacer.remove(); 66 | } 67 | } 68 | scope.onClick = function() { 69 | input.click(); 70 | }; 71 | } 72 | 73 | angular.element(element[0].querySelector('.separator-input')).on('keyup', function(e) { 74 | if ( scope.content != null ) { 75 | var content = { 76 | csv: scope.content, 77 | header: scope.header, 78 | separator: e.target.value, 79 | encoding: scope.encoding 80 | }; 81 | scope.result = csvToJSON(content); 82 | scope.$apply(); 83 | if ( typeof scope.callback === 'function' ) { 84 | if ( scope.callback != null) { 85 | scope.callback(e); 86 | } 87 | } 88 | } 89 | }); 90 | 91 | element.on('change', function(onChangeEvent) { 92 | if (!onChangeEvent.target.files.length){ 93 | return; 94 | } 95 | 96 | if (onChangeEvent.target.files[0].size > scope.acceptSize){ 97 | if ( typeof scope.acceptSizeExceedCallback === 'function' ) { 98 | scope.acceptSizeExceedCallback(onChangeEvent.target.files[0]); 99 | } 100 | return; 101 | } 102 | 103 | scope.filename = onChangeEvent.target.files[0].name; 104 | var reader = new FileReader(); 105 | reader.onload = function(onLoadEvent) { 106 | scope.$apply(function() { 107 | var content = { 108 | csv: onLoadEvent.target.result.replace(/\r\n|\r/g,'\n'), 109 | header: scope.header, 110 | separator: scope.separator 111 | }; 112 | scope.content = content.csv; 113 | scope.result = csvToJSON(content); 114 | scope.result.filename = scope.filename; 115 | scope.$$postDigest(function(){ 116 | if ( typeof scope.callback === 'function' ) { 117 | if ( scope.callback != null) { 118 | scope.callback(onChangeEvent); 119 | } 120 | } 121 | }); 122 | }); 123 | }; 124 | 125 | if ( (onChangeEvent.target.type === "file") && (onChangeEvent.target.files != null || onChangeEvent.srcElement.files != null) ) { 126 | reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0], scope.encoding); 127 | } else { 128 | if ( scope.content != null ) { 129 | var content = { 130 | csv: scope.content, 131 | header: !scope.header, 132 | separator: scope.separator 133 | }; 134 | scope.result = csvToJSON(content); 135 | scope.$$postDigest(function(){ 136 | if ( typeof scope.callback === 'function' ) { 137 | if ( scope.callback != null) { 138 | scope.callback(onChangeEvent); 139 | } 140 | } 141 | }); 142 | } 143 | } 144 | }); 145 | 146 | var csvToJSON = function(content) { 147 | var lines=content.csv.split(new RegExp('\n(?![^"]*"(?:(?:[^"]*"){2})*[^"]*$)')); 148 | var result = []; 149 | var start = 0; 150 | var columnCount = lines[0].split(content.separator).length; 151 | 152 | var headers = []; 153 | if (content.header) { 154 | headers=lines[0].split(content.separator); 155 | start = 1; 156 | } 157 | 158 | for (var i=start; i", 4 | "version": "0.0.38", 5 | "main": "./lib/angular-csv-import.js", 6 | "engines": { 7 | "node": ">= 0.10.0" 8 | }, 9 | "devDependencies": { 10 | "grunt": "^0.4.1", 11 | "grunt-autoprefixer": "^0.7.3", 12 | "grunt-bump": "0.0.14", 13 | "grunt-concurrent": "^0.5.0", 14 | "grunt-contrib-clean": "^0.5.0", 15 | "grunt-contrib-concat": "^0.4.0", 16 | "grunt-contrib-connect": "^0.7.1", 17 | "grunt-contrib-copy": "^0.5.0", 18 | "grunt-contrib-cssmin": "^0.9.0", 19 | "grunt-contrib-htmlmin": "^0.3.0", 20 | "grunt-contrib-jshint": "^0.10.0", 21 | "grunt-contrib-uglify": "^0.4.0", 22 | "grunt-contrib-watch": "^0.6.1", 23 | "grunt-filerev": "^0.2.1", 24 | "grunt-newer": "^0.7.0", 25 | "grunt-ngmin": "^0.0.3", 26 | "grunt-usemin": "^2.1.1", 27 | "grunt-wiredep": "^1.7.0", 28 | "jshint-stylish": "^0.2.0", 29 | "load-grunt-tasks": "^0.4.0", 30 | "time-grunt": "^0.3.1", 31 | "grunt-gh-pages": "^0.9.1" 32 | } 33 | } 34 | --------------------------------------------------------------------------------