├── .gitignore ├── .jshintrc ├── .circleci └── config.yml ├── LICENSE-MIT ├── tasks ├── fontello.js └── lib │ └── fontello.js ├── package.json ├── Gruntfile.js ├── README.md └── test ├── fontello_test.js └── fontello-config.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | tmp 4 | .idea 5 | test/output 6 | session 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 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 | "node": true 13 | } 14 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | - image: circleci/node:7.10 10 | 11 | working_directory: ~/repo 12 | 13 | steps: 14 | - checkout 15 | 16 | # Download and cache dependencies 17 | - restore_cache: 18 | keys: 19 | - v1-dependencies-{{ checksum "package.json" }} 20 | # fallback to using the latest cache if no exact match is found 21 | - v1-dependencies- 22 | 23 | - run: npm install 24 | 25 | - save_cache: 26 | paths: 27 | - node_modules 28 | key: v1-dependencies-{{ checksum "package.json" }} 29 | 30 | # lint code 31 | - run: npm run lint 32 | # run tests 33 | - run: npm run test 34 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jubal Mabaquiao 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /tasks/fontello.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-fontello 3 | * https://github.com/jubal/grunt-fontello 4 | * 5 | * Copyright (c) 2013 Jubal Mabaquiao 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var fontello = require('./lib/fontello'); 12 | var async = require('async'); 13 | 14 | module.exports = function(grunt){ 15 | 16 | grunt.registerMultiTask('fontello', 'Download font library from fontello.com', function(){ 17 | 18 | var done = this.async(), 19 | options = this.options({ 20 | host : 'http://fontello.com', 21 | config : 'config.json', 22 | fonts : 'fonts', 23 | styles : 'css', 24 | exclude : [], 25 | zip : false, 26 | preprocessor : 'none', 27 | force : true, 28 | cssFontPath : undefined, 29 | prefix : 'fontello' 30 | }); 31 | 32 | var recipe = [ 33 | fontello.deprecated.bind(null, options), 34 | fontello.init, 35 | fontello.check, 36 | fontello.post, 37 | fontello.fetch, 38 | fontello.fontPath 39 | ]; 40 | 41 | async.waterfall(recipe, function(error, results){ 42 | if(error) { grunt.log.error(error); } 43 | else { 44 | grunt.log.ok(results); 45 | done(); 46 | } 47 | }); 48 | 49 | }); 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-fontello", 3 | "description": "Download font library from fontello.com", 4 | "version": "0.3.7", 5 | "homepage": "https://github.com/jubalm/grunt-fontello", 6 | "author": { 7 | "name": "Jubal Mabaquiao", 8 | "email": "jubal.mabaquiao@gmail.com", 9 | "url": "jubalm.github.com" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/jubalm/grunt-fontello.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/jubalm/grunt-fontello/issues" 17 | }, 18 | "licenses": [ 19 | { 20 | "type": "MIT", 21 | "url": "https://github.com/jubalm/grunt-fontello/blob/master/LICENSE-MIT" 22 | } 23 | ], 24 | "engines": { 25 | "node": ">= 0.8.0" 26 | }, 27 | "scripts": { 28 | "test": "grunt test" 29 | }, 30 | "devDependencies": { 31 | "grunt-contrib-clean": "~0.4.0", 32 | "grunt-contrib-jshint": "^1.1.0", 33 | "grunt-contrib-nodeunit": "~0.2.0", 34 | "grunt-contrib-watch": "^1.1.0" 35 | }, 36 | "peerDependencies": {}, 37 | "keywords": [ 38 | "gruntplugin", 39 | "font-icon", 40 | "fontello", 41 | "icon", 42 | "font" 43 | ], 44 | "dependencies": { 45 | "async": "~0.2.9", 46 | "grunt": "~1.0.1", 47 | "mkdirp": "~0.3.5", 48 | "needle": "~0.11.0", 49 | "normalize-path": "^2.1.1", 50 | "unzipper": "~0.10.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /* 2 | * grunt-fontello 3 | * https://github.com/jubal/grunt-fontello 4 | * 5 | * Copyright (c) 2013 Jubal Mabaquiao 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | module.exports = function(grunt) { 12 | 13 | // Project configuration. 14 | grunt.initConfig({ 15 | jshint: { 16 | options: { jshintrc: '.jshintrc' }, 17 | all: [ 18 | 'Gruntfile.js', 19 | 'tasks/*.js', 20 | '<%= nodeunit.tests %>' 21 | ] 22 | }, 23 | 24 | // Before generating any new files, remove any previously-created files. 25 | clean: { 26 | tests: ['test/output'] 27 | }, 28 | 29 | // Configuration to be run (and then tested). 30 | fontello: { 31 | options: { 32 | config: 'test/fontello-config.json', 33 | fonts: 'test/output/fonts', 34 | styles: 'test/output/styles' 35 | }, 36 | css: { 37 | options: { preprocessor: 'none' } 38 | }, 39 | less: { 40 | options: { preprocessor: 'less' } 41 | }, 42 | scss: { 43 | options: { preprocessor: 'scss' } 44 | }, 45 | exclude: { 46 | options: { 47 | exclude: [/fontello-ie7*/, 'fontello.ttf'], 48 | fonts: 'test/output/fonts/exclude', 49 | styles: 'test/output/styles/exclude' 50 | } 51 | }, 52 | cssFontPath: { 53 | options: { 54 | cssFontPath: 'foobar', 55 | styles: 'test/output/styles/cssFontPath' 56 | } 57 | }, 58 | prefix: { 59 | options: { 60 | prefix: 'foobar', 61 | styles: 'test/output/styles/prefix' 62 | } 63 | }, 64 | zip: { 65 | options: { 66 | fonts: '', 67 | styles: '', 68 | zip: './test/output/zip' 69 | } 70 | } 71 | }, 72 | 73 | // Unit tests. 74 | nodeunit: { 75 | tests: ['test/*_test.js'] 76 | }, 77 | 78 | watch: { 79 | dist: { 80 | files: ['test/**/*.js', 'tasks/**/*.js', 'Gruntfile.js'], 81 | tasks: ['test'] 82 | } 83 | } 84 | }); 85 | 86 | // Actually load this plugin's task(s). 87 | grunt.loadTasks('tasks'); 88 | 89 | // These plugins provide necessary tasks. 90 | grunt.loadNpmTasks('grunt-contrib-jshint'); 91 | grunt.loadNpmTasks('grunt-contrib-clean'); 92 | grunt.loadNpmTasks('grunt-contrib-nodeunit'); 93 | grunt.loadNpmTasks('grunt-contrib-watch'); 94 | 95 | // Whenever the "test" task is run, first clean the "tmp" dir, then run this 96 | // plugin's task(s), then test the result. 97 | grunt.registerTask('test', ['clean', 'fontello', 'nodeunit']); 98 | 99 | // By default, lint and run all tests. 100 | grunt.registerTask('default', ['jshint', 'test', 'watch']); 101 | 102 | }; 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grunt-fontello 2 | 3 | > donwload font icons from fontello.com 4 | 5 | ## Getting Started 6 | This plugin requires Grunt `~0.4.1` 7 | 8 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: 9 | 10 | ```shell 11 | npm install grunt-fontello --save-dev 12 | ``` 13 | 14 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: 15 | 16 | ```js 17 | grunt.loadNpmTasks('grunt-fontello'); 18 | ``` 19 | 20 | ## The "fontello" task 21 | 22 | ### Overview 23 | In your project's Gruntfile, add a section named `fontello` to the data object passed into `grunt.initConfig()`. 24 | 25 | ```js 26 | grunt.initConfig({ 27 | fontello: { 28 | dist: { 29 | options: { 30 | config : 'config.json', 31 | fonts : 'output/fonts', 32 | styles : 'output/css', 33 | preprocessor : 'scss', 34 | force : true 35 | } 36 | } 37 | } 38 | }) 39 | ``` 40 | 41 | ### Options 42 | 43 | #### options.config 44 | Type: `String` 45 | Default value: `"config.json"` 46 | 47 | Path to your config.json file. Generate custom font icons [here](http://www.fontello.com). 48 | 49 | #### options.zip 50 | Type: `String` 51 | Default value: `"."` 52 | 53 | Folder to extract the full archive. 54 | 55 | #### options.fonts 56 | Type: `String` 57 | Default value: `"fonts"` 58 | 59 | Path to extract font files (`*.eot`, `*.woff`, `*.svg`, `*.ttf`). 60 | 61 | #### options.styles 62 | Type: `String` 63 | Default value: `"css"` 64 | 65 | Path to extract the stylesheets to. 66 | 67 | #### options.preprocessor 68 | Type: `String` 69 | Default value: `none` 70 | 71 | By default the outputted stylesheet will be _.css_. Changing this to `less` or `scss` will 72 | change the output to _.less_ or _.scss_ respectively. 73 | 74 | #### options.force 75 | Type: `Boolean` 76 | Default value: `false` 77 | 78 | By default, if the folder specified in _options.fonts_, _options.zip_ and _options.styles_ do not exist, the task will throw an error. Setting this option to `true` will create the directory structure specified. 79 | 80 | #### options.exclude 81 | Type: `Array` 82 | Default value: `[]` 83 | 84 | An array of names of files which should be excluded. Accepts strings and regular expressions. 85 | 86 | #### options.cssFontPath 87 | Type: `String` 88 | Default value: `undefined` 89 | 90 | An explicit path to where the fonts are relative to the _.css_/_.scss_ file. 91 | 92 | #### options.prefix 93 | Type: `String` 94 | Default value: `fontello` 95 | 96 | A string representing the prefix of the stylesheets generated by fontello. 97 | 98 | ### Example 99 | 100 | #### Multiple Targets 101 | ```js 102 | grunt.initConfig({ 103 | fontello: { 104 | options: { 105 | preprocessor : 'scss', 106 | force : true 107 | }, 108 | dist: { 109 | options: { 110 | fonts : 'output/fonts', 111 | styles : 'output/css', 112 | } 113 | }, 114 | dev: { 115 | options: { 116 | config : 'test/config.json', 117 | fonts : 'test/output/fonts', 118 | styles : 'test/output/css', 119 | } 120 | } 121 | } 122 | }) 123 | 124 | grunt.loadNpmTasks('grunt-fontello'); 125 | grunt.registerTask('default', ['fontello:dist']); 126 | ``` 127 | 128 | #### Exclude files 129 | ```js 130 | grunt.initConfig({ 131 | fontello: { 132 | dist: { 133 | options: { 134 | fonts : 'output/fonts', 135 | styles : 'output/css', 136 | exclude : ['animation.css', 'fontello-ie7-codes.css', 'fontello.eot'], 137 | } 138 | } 139 | } 140 | }) 141 | ``` 142 | -------------------------------------------------------------------------------- /test/fontello_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var grunt = require('grunt'); 5 | 6 | exports.fontello = { 7 | setUp: function(done) { 8 | this.extractPath = grunt.config.get('fontello.zip.options.zip'); 9 | this.fontsPath = grunt.config.get('fontello.options.fonts'); 10 | this.stylesPath = grunt.config.get('fontello.options.styles'); 11 | done(); 12 | }, 13 | fonts: function(test) { 14 | test.ok(grunt.file.exists(this.fontsPath + '/fontello.eot'), '.eot font file missing'); 15 | test.ok(grunt.file.exists(this.fontsPath + '/fontello.svg'), '.svg font file missing'); 16 | test.ok(grunt.file.exists(this.fontsPath + '/fontello.ttf'), '.ttf font file missing'); 17 | test.ok(grunt.file.exists(this.fontsPath + '/fontello.woff'), '.woff font file missing'); 18 | test.ok(grunt.file.exists(this.fontsPath + '/fontello.woff2'), '.woff2 font file missing'); 19 | test.done(); 20 | }, 21 | cssStylesheets: function(test) { 22 | test.ok(grunt.file.exists(this.stylesPath + '/animation.css'), 'Animations stylesheet missing'); 23 | test.ok(grunt.file.exists(this.stylesPath + '/fontello.css'), 'Fontello stylesheet missing'); 24 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-codes.css'), 'Codes stylesheet missing'); 25 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-embedded.css'), 'Embedded stylesheet missing'); 26 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-ie7.css'), 'IE7 stylesheet missing'); 27 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-ie7-codes.css'), 'IE7 codes stylesheet missing'); 28 | test.done(); 29 | }, 30 | lessStylesheets: function(test) { 31 | test.ok(grunt.file.exists(this.stylesPath + '/animation.less'), 'Animations stylesheet missing'); 32 | test.ok(grunt.file.exists(this.stylesPath + '/fontello.less'), 'Fontello stylesheet missing'); 33 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-codes.less'), 'Codes stylesheet missing'); 34 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-embedded.less'), 'Embedded stylesheet missing'); 35 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-ie7.less'), 'IE7 stylesheet missing'); 36 | test.ok(grunt.file.exists(this.stylesPath + '/fontello-ie7-codes.less'), 'IE7 codes stylesheet missing'); 37 | test.done(); 38 | }, 39 | scssStylesheets: function(test) { 40 | test.ok(grunt.file.exists(this.stylesPath + '/_animation.scss'), 'Animations stylesheet missing'); 41 | test.ok(grunt.file.exists(this.stylesPath + '/_fontello.scss'), 'Fontello stylesheet missing'); 42 | test.ok(grunt.file.exists(this.stylesPath + '/_fontello-codes.scss'), 'Codes stylesheet missing'); 43 | test.ok(grunt.file.exists(this.stylesPath + '/_fontello-embedded.scss'), 'Embedded stylesheet missing'); 44 | test.ok(grunt.file.exists(this.stylesPath + '/_fontello-ie7.scss'), 'IE7 stylesheet missing'); 45 | test.ok(grunt.file.exists(this.stylesPath + '/_fontello-ie7-codes.scss'), 'IE7 codes stylesheet missing'); 46 | test.done(); 47 | }, 48 | exclude: function(test) { 49 | test.ok(!grunt.file.exists(this.fonts + '/exclude/fontello.ttf'), '.ttf font file present while excluded'); 50 | test.ok(!grunt.file.exists(this.stylesPath + '/exclude/fontello-ie7.css'), 'IE7 stylesheet present while excluded'); 51 | test.ok(!grunt.file.exists(this.stylesPath + '/exclude/fontello-ie7-codes.css'), 'IE7 codes stylesheet present while excluded'); 52 | test.done(); 53 | }, 54 | cssFontPath: function(test) { 55 | var stylesheet = fs.readFileSync(this.stylesPath + '/cssFontPath/fontello.css', { encoding: 'utf-8' }); 56 | test.ok(/url\('foobar/.test(stylesheet), 'CSS font path not changed'); 57 | test.done(); 58 | }, 59 | prefix: function(test) { 60 | test.ok(grunt.file.exists(this.stylesPath + '/prefix/foobar.css'), 'foobar stylesheet missing'); 61 | test.ok(grunt.file.exists(this.stylesPath + '/prefix/foobar-codes.css'), 'foobar codes stylesheet missing'); 62 | test.ok(grunt.file.exists(this.stylesPath + '/prefix/foobar-embedded.css'), 'foobar embedded stylesheet missing'); 63 | test.ok(grunt.file.exists(this.stylesPath + '/prefix/foobar-ie7.css'), 'foobar IE7 stylesheet missing'); 64 | test.ok(grunt.file.exists(this.stylesPath + '/prefix/foobar-ie7-codes.css'), 'foobar IE7 codes stylesheet missing'); 65 | test.done(); 66 | }, 67 | zip: function(test) { 68 | test.ok(grunt.file.isDir(this.extractPath), 'Unzip extract path missing'); 69 | test.done(); 70 | } 71 | }; 72 | -------------------------------------------------------------------------------- /test/fontello-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "css_prefix_text": "icon-", 4 | "css_use_suffix": false, 5 | "hinting": true, 6 | "units_per_em": 1000, 7 | "ascent": 850, 8 | "copyright": "undefined", 9 | "fullname": "undefined", 10 | "glyphs": [ 11 | { 12 | "uid": "9bd60140934a1eb9236fd7a8ab1ff6ba", 13 | "css": "spin4", 14 | "code": 59425, 15 | "src": "fontelico" 16 | }, 17 | { 18 | "uid": "dcedf50ab1ede3283d7a6c70e2fe32f3", 19 | "css": "chat", 20 | "code": 59392, 21 | "src": "fontawesome" 22 | }, 23 | { 24 | "uid": "559647a6f430b3aeadbecd67194451dd", 25 | "css": "menu-1", 26 | "code": 59406, 27 | "src": "fontawesome" 28 | }, 29 | { 30 | "uid": "757afacc32d82967975cbb3b45cfb41b", 31 | "css": "desktop", 32 | "code": 59415, 33 | "src": "fontawesome" 34 | }, 35 | { 36 | "uid": "500fc1f109021e4b1de4deda2f7ed399", 37 | "css": "laptop", 38 | "code": 59416, 39 | "src": "fontawesome" 40 | }, 41 | { 42 | "uid": "f001fc3d4daa7da078e8c971e4f36977", 43 | "css": "tablet", 44 | "code": 59417, 45 | "src": "fontawesome" 46 | }, 47 | { 48 | "uid": "0357f7abbc0babf43509669f332e41e6", 49 | "css": "mobile", 50 | "code": 59418, 51 | "src": "fontawesome" 52 | }, 53 | { 54 | "uid": "0f444c61b0d2c9966016d7ddb12f5837", 55 | "css": "beaker", 56 | "code": 59393, 57 | "src": "fontawesome" 58 | }, 59 | { 60 | "uid": "fa10777b2d88cc64cd6e4f26ef0e5264", 61 | "css": "terminal", 62 | "code": 59424, 63 | "src": "fontawesome" 64 | }, 65 | { 66 | "uid": "5f0f183e241d15cbe486bff88b188dff", 67 | "css": "puzzle", 68 | "code": 59396, 69 | "src": "fontawesome" 70 | }, 71 | { 72 | "uid": "e9fa538fd5913046497ac148e27cd8ea", 73 | "css": "apple", 74 | "code": 59395, 75 | "src": "fontawesome" 76 | }, 77 | { 78 | "uid": "169f51b7e405de8c03cf85a6e8c740ab", 79 | "css": "bitbucket", 80 | "code": 59394, 81 | "src": "fontawesome" 82 | }, 83 | { 84 | "uid": "01c946ce2ed5500e0a918f2b3a7d1923", 85 | "css": "css3", 86 | "code": 59403, 87 | "src": "fontawesome" 88 | }, 89 | { 90 | "uid": "ff44f01f60948555026580eedf1e39bb", 91 | "css": "html5", 92 | "code": 59402, 93 | "src": "fontawesome" 94 | }, 95 | { 96 | "uid": "b846892636bd74112998bb159bdddf27", 97 | "css": "trello", 98 | "code": 59423, 99 | "src": "fontawesome" 100 | }, 101 | { 102 | "uid": "c709da589c923ba3c2ad48d9fc563e93", 103 | "css": "cancel", 104 | "code": 59404, 105 | "src": "entypo" 106 | }, 107 | { 108 | "uid": "70370693ada58ef0a60fa0984fe8d52a", 109 | "css": "plus", 110 | "code": 59419, 111 | "src": "entypo" 112 | }, 113 | { 114 | "uid": "1256e3054823e304d7e452a589cf8bb8", 115 | "css": "minus", 116 | "code": 59420, 117 | "src": "entypo" 118 | }, 119 | { 120 | "uid": "b6f32db98a3de777f5ae3005191b1831", 121 | "css": "code", 122 | "code": 59421, 123 | "src": "entypo" 124 | }, 125 | { 126 | "uid": "390d6d13398cbf8c8c3c5493f7d34088", 127 | "css": "export", 128 | "code": 59422, 129 | "src": "entypo" 130 | }, 131 | { 132 | "uid": "289b5f92f23acf1059c93fbf401c1ad5", 133 | "css": "down", 134 | "code": 59401, 135 | "src": "entypo" 136 | }, 137 | { 138 | "uid": "884cfc3e6e2d456dd2a2ca0dbb9e6337", 139 | "css": "left", 140 | "code": 59400, 141 | "src": "entypo" 142 | }, 143 | { 144 | "uid": "004882ab2d5c418c5b2060e80596279b", 145 | "css": "right", 146 | "code": 59399, 147 | "src": "entypo" 148 | }, 149 | { 150 | "uid": "0805cca616b3c12714f35af4d0912c10", 151 | "css": "up", 152 | "code": 59408, 153 | "src": "entypo" 154 | }, 155 | { 156 | "uid": "db112402805d9dadc01ce009fbfdb914", 157 | "css": "paper-plane", 158 | "code": 59405, 159 | "src": "entypo" 160 | }, 161 | { 162 | "uid": "d090355c31f497b61d676416c1fd39fb", 163 | "css": "twitter-1", 164 | "code": 59407, 165 | "src": "entypo" 166 | }, 167 | { 168 | "uid": "bc50457410acf467b8b5721240768742", 169 | "css": "facebook", 170 | "code": 59397, 171 | "src": "entypo" 172 | }, 173 | { 174 | "uid": "7132e1233bc16cd1b6efe7e29d3613a5", 175 | "css": "linkedin", 176 | "code": 59398, 177 | "src": "entypo" 178 | }, 179 | { 180 | "uid": "28ccaf022b8363aeaa5b86f66e1f5173", 181 | "css": "skype", 182 | "code": 59409, 183 | "src": "entypo" 184 | }, 185 | { 186 | "uid": "84f3880057574e968053d6d6c8a7b216", 187 | "css": "behance", 188 | "code": 59410, 189 | "src": "entypo" 190 | }, 191 | { 192 | "uid": "492fe0ef4cb41d4e4de8502897685399", 193 | "css": "cafe", 194 | "code": 59411, 195 | "src": "maki" 196 | }, 197 | { 198 | "uid": "288a62ca532f76053c4a834ba3746ea2", 199 | "css": "w3c", 200 | "code": 59412, 201 | "src": "zocial" 202 | }, 203 | { 204 | "uid": "0636c283a9822288a767609062bbf4a4", 205 | "css": "wordpress", 206 | "code": 59413, 207 | "src": "zocial" 208 | }, 209 | { 210 | "uid": "e7d17d4d07756f4ab5eb690eea1275ca", 211 | "css": "stackoverflow", 212 | "code": 59414, 213 | "src": "zocial" 214 | } 215 | ] 216 | } -------------------------------------------------------------------------------- /tasks/lib/fontello.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var os = require('os'); 4 | var fs = require('fs'); 5 | var path = require('path'); 6 | var async = require('async'); 7 | var needle = require('needle'); 8 | var unzip = require('unzipper'); 9 | var mkdirp = require('mkdirp'); 10 | var grunt = require('grunt'); 11 | var normalize = require('normalize-path'); 12 | 13 | /* Fontello API parameters */ 14 | var getOptions = { 15 | follow: 10 16 | }; 17 | 18 | /* Verify or build paths */ 19 | var processPath = function(options, dir, callback){ 20 | 21 | fs.exists(dir, function(exists){ 22 | 23 | if(!exists) { 24 | if(!options.force) { 25 | callback(dir + ' missing! use `force:true` to create'); 26 | } 27 | else { 28 | // Force create path 29 | mkdirp(dir, function(err){ 30 | if (err) { 31 | callback(err); 32 | } 33 | else { 34 | callback(null, dir + ' created!'); 35 | } 36 | }); 37 | } 38 | } 39 | else { 40 | callback(null, dir + ' verified!'); 41 | } 42 | 43 | }); 44 | 45 | }; 46 | 47 | /* Get session */ 48 | var getSession = function(){ 49 | 50 | var src = path.resolve(os.tmpdir(), 'grunt-fontello-session'); 51 | 52 | // Make sure the session file exists, return `null` otherwise. 53 | if(!fs.existsSync(src)) 54 | return null; 55 | 56 | // Read session from the session file. 57 | return fs.readFileSync(src, { encoding: 'utf-8' }); 58 | 59 | } 60 | 61 | /* Set session */ 62 | var setSession = function(session){ 63 | 64 | var dest = path.resolve(os.tmpdir(), 'grunt-fontello-session'); 65 | 66 | // Write session to the session file since the Fontello 67 | // api dislikes custom members. 68 | fs.writeFileSync(dest, session); 69 | 70 | } 71 | 72 | /* Set relative font path */ 73 | var setFontPath = function(options, callback){ 74 | 75 | var css2FontPath = options.cssFontPath || normalize(path.relative(options.styles, options.fonts)); 76 | grunt.log.write('Processing font path...'); 77 | 78 | try { 79 | fs.readdir(options.styles, function(err, files){ 80 | 81 | for(var i in files) { 82 | if(!files.hasOwnProperty(i)) 83 | continue; 84 | 85 | var filePath = path.join(options.styles, files[i]); 86 | 87 | if(fs.statSync(filePath).isDirectory()) 88 | continue; 89 | 90 | var content = fs.readFileSync(filePath); 91 | fs.writeFileSync(filePath, content.toString().replace(/\.\.\/font/g, css2FontPath)); 92 | } 93 | 94 | }); 95 | 96 | grunt.log.debug('Font path is ' + css2FontPath); 97 | grunt.log.ok(); 98 | callback(null, 'extract complete'); 99 | } catch(err) { 100 | grunt.log.error(err); 101 | grunt.log.fail(); 102 | callback(err); 103 | } 104 | 105 | } 106 | 107 | /* 108 | * Display Deprecated Message(s) 109 | * @callback: options 110 | * */ 111 | var deprecated = function(options, callback){ 112 | if(options.scss) 113 | grunt.log.warn('You\'re using the deprecated option "scss", please switch to "preprocessor" as soon as possible'); 114 | 115 | callback(null, options); 116 | }; 117 | 118 | /* 119 | * Initial Checks 120 | * @callback: options 121 | * */ 122 | var init = function(options, callback){ 123 | 124 | grunt.log.write('Verify paths...'); 125 | var tests = [ 126 | processPath.bind(null, options, options.fonts), 127 | processPath.bind(null, options, options.styles) 128 | ]; 129 | 130 | async.parallel(options.styles ? tests : [tests[0]], function(err, results){ 131 | 132 | if(err) { 133 | grunt.log.error(err); 134 | callback(err); 135 | } 136 | else { 137 | grunt.log.ok(); 138 | results.forEach(function(result){ 139 | grunt.log.debug(result); 140 | }); 141 | callback(null, options); 142 | } 143 | 144 | }); 145 | 146 | }; 147 | 148 | /* 149 | * Check Session 150 | * URL: http://fontello.com 151 | * GET: http://fontello.com/SESSIONID/get 152 | * @callback: bool representing expiration of session 153 | * */ 154 | var checkSession = function(options, callback){ 155 | 156 | var expired = false; 157 | var session = getSession(); 158 | 159 | grunt.log.write('Checking session...'); 160 | if(session !== null) { 161 | needle.get(options.host + '/' + session + '/get', getOptions, function(err, response, body){ 162 | 163 | if(response.statusCode === 500) 164 | expired = true; 165 | 166 | grunt.log.ok(); 167 | callback(null, options, expired); 168 | 169 | }); 170 | } 171 | else { 172 | callback(null, options, true); 173 | } 174 | 175 | }; 176 | 177 | /* 178 | * Create Session 179 | * URL: http://fontello.com 180 | * POST: config.json 181 | * @callback: session id 182 | * */ 183 | var createSession = function(options, expired, callback){ 184 | 185 | var data = { 186 | config: { 187 | file: options.config, 188 | content_type: 'application/json' 189 | } 190 | }; 191 | 192 | var session = getSession(); 193 | 194 | if (session !== null && !expired) { 195 | callback(null, options, session); 196 | } 197 | else { 198 | grunt.log.write('Creating session...'); 199 | needle.post( options.host, data, { multipart: true }, function(err, response, body){ 200 | 201 | if (err) { 202 | grunt.log.error(); 203 | callback(err); 204 | } 205 | else { 206 | grunt.log.ok(); 207 | grunt.log.debug('sid: ' + body); 208 | 209 | // Store the new sid and continue 210 | setSession(body); 211 | callback(null, options, body); 212 | } 213 | 214 | }); 215 | } 216 | 217 | }; 218 | 219 | /* 220 | * Download Archive 221 | * URL: http://fontello.com 222 | * GET: http://fontello.com/SESSIONID/get 223 | * callback: fetch/download result 224 | * */ 225 | var fetchStream = function(options, session, callback){ 226 | 227 | // The Fontello api outputs an error message instead of a session id if the 228 | // config file contains unexpected data. Pass that error on. 229 | if(/Invalid/.test(session)) 230 | throw new Error(session); 231 | 232 | var tempConfig = path.resolve(os.tmpdir(), 'config-tmp.json'); 233 | var tempZip = path.resolve(os.tmpdir(), 'fontello-tmp.zip'); 234 | 235 | grunt.log.write('Fetching archive...'); 236 | needle.get(options.host + '/' + session + '/get', getOptions, function(err, response, body){ 237 | 238 | if(err) 239 | throw err; 240 | 241 | if(response.statusCode == 404) { 242 | setSession(options, ''); 243 | createSession(options, fetchStream); 244 | } else { 245 | fs.writeFileSync(tempZip, body); 246 | var readStream = fs.createReadStream(tempZip); 247 | 248 | /* Extract Files */ 249 | if(options.fonts || options.styles) { 250 | return readStream.pipe(unzip.Parse()) 251 | // TODO: fix inconsistent return point 252 | .on('entry', function(entry){ 253 | var ext = path.extname(entry.path); 254 | var name = path.basename(entry.path); 255 | 256 | if(entry.type === 'File') { 257 | for(var rule of options.exclude) { 258 | if(rule === name || name.match(rule)) { 259 | grunt.verbose.writeln('Ignored ', entry.path); 260 | entry.autodrain(); 261 | return; 262 | } 263 | } 264 | 265 | switch(ext) { 266 | // Extract Fonts 267 | case '.woff':case '.svg': case '.ttf': case '.eot': case '.woff2': 268 | var fontPath = path.join(options.fonts, path.basename(entry.path)); 269 | return entry.pipe(fs.createWriteStream(fontPath)); 270 | // Extract CSS 271 | case '.css': 272 | if (options.styles) { 273 | var basename = path.basename(entry.path).replace('fontello', options.prefix); 274 | var cssPath; 275 | switch(options.preprocessor.toLowerCase()) { 276 | case 'none': 277 | if(options.scss === true) { 278 | cssPath = path.join(options.styles, '_' + basename.replace(ext, '.scss')); 279 | } else { 280 | cssPath = path.join(options.styles, basename); 281 | } 282 | break; 283 | case 'less': 284 | cssPath = path.join(options.styles, basename.replace(ext, '.less')); 285 | break; 286 | case 'scss': 287 | cssPath = path.join(options.styles, '_' + basename.replace(ext, '.scss')); 288 | break; 289 | default: 290 | grunt.fail.warn('Unknown preprocessor "' + options.output + '"'); 291 | return; 292 | } 293 | 294 | return entry.pipe(fs.createWriteStream(cssPath)); 295 | } 296 | // Drain everything else 297 | default: 298 | grunt.verbose.writeln('Ignored ', entry.path); 299 | entry.autodrain(); 300 | } 301 | } 302 | }) 303 | .on('close', function(){ 304 | fs.unlinkSync(tempZip); 305 | grunt.log.ok(); 306 | callback(null, options); 307 | }); 308 | } 309 | 310 | /* Extract full archive */ 311 | return readStream.pipe(unzip.Extract({ path: options.zip })) 312 | .on('close', function(){ 313 | grunt.log.ok(); 314 | fs.unlinkSync(tempZip); 315 | callback(null, options); 316 | }); 317 | } 318 | 319 | }); 320 | 321 | }; 322 | 323 | module.exports = { 324 | deprecated : deprecated, 325 | init : init, 326 | check : checkSession, 327 | post : createSession, 328 | fetch : fetchStream, 329 | fontPath : setFontPath 330 | }; 331 | --------------------------------------------------------------------------------