Permalink
Browse files

Added support for UTF-8 encoding

I was working on a mixin to inline SVG's with the ability to set `fill` colors. Inlining of SVG's performs better when we skip the base64 encoding, which wasn't yet enabled in Stylus, like it is in LESS for example.

With my update you can just call `embedurl("path/to/file.svg", "utf8")` (or whatever you've defined as the alias for Stylus' url method) and it'll return the `url(` string you can use with `background-image`.

- Added a test & updated the docs
- Fixed some issues that were causing tests to fail on Windows.
- All test files with `url` were using Stylus' url method when it didn't need to so I changed the `define` from `url` to `embedurl`.
  • Loading branch information...
1 parent 1fdb38e commit 7ad33ab800b99bc7af0da46b49e6394bd3a5aeb6 @the0neWhoKnocks the0neWhoKnocks committed Jan 9, 2016
View
18 Contributing.md 100644 → 100755
@@ -25,7 +25,7 @@ Please note that this project is released with a [Contributor Code of Conduct](C
## How you can help
-You're welcomed to:
+You're welcome to:
- send pull requests;
- report bugs;
@@ -63,7 +63,7 @@ We'll close your PR or issue if:
Please do not take offense if your ticket is closed. We're only trying to keep the number of issues manageable.
-### Filling bugs
+### Filing bugs
If you found an error, typo, or any other flaw in the project, please report it using [GitHub Issues](https://github.com/stylus/stylus/issues). Try searching the issues to see if there is an existing report of your bug, and if you'd find it, you could bump it by adding your test case there.
@@ -133,6 +133,20 @@ Each minor release should be first compiled into `rc-`branch. Minor release *sho
Patch releases don't need their own `rc` branches, as they could be released from the `dev` branch.
+### Adding tests
+
+First you want to make sure to run the below commands
+
+```
+npm install
+# for a more verbose output you can install mocha at a global level
+npm install mocha -g
+```
+
+Then at the root of the project you can run `npm test` or `mocha` to execute all tests. If you need to add or edit tests, they are located in the `test/cases` directory.
+
+Each `.styl` file has a corresponding `.css` file. The `.styl` is the mock, and the `.css` is the expected result.
+
* * *
View
40 docs/functions.url.md 100644 → 100755
@@ -15,25 +15,37 @@ The function itself is available via `require('stylus').url`. It accepts an `opt
The `.define(name, callback)` method assigned a JavaScript function that can be called from Stylus source. In this case, since our images are in `./css/images`, we can ignore the `paths` option (by default image lookups are performed relative to the file being rendered). But if desired, this behavior can be altered:
- stylus(str)
- .set('filename', __dirname + '/css/test.styl')
- .define('url', stylus.url())
- .render(function(err, css){
-
- });
+```javascript
+stylus(str)
+ .set('filename', __dirname + '/css/test.styl')
+ .define('embedurl', stylus.url())
+ .render(function(err, css){
+ // render it
+ });
+```
-For example, imagine our images live in `./public/images`. We want to use `url(images/tobi.png)`. We could pass `paths` our public directory, so that it becomes part of the lookup process.
+For example, imagine our images live in `./public/images`. We want to use `url(images/tobi.png)`. We could pass `paths` our public directory, so that it becomes part of the lookup process.
Likewise, if instead we wanted `url(tobi.png)`, we could pass `paths: [__dirname + '/public/images']`.
- stylus(str)
- .set('filename', __dirname + '/css/test.styl')
- .define('url', stylus.url({ paths: [__dirname + '/public'] }))
- .render(function(err, css){
+```javascript
+stylus(str)
+ .set('filename', __dirname + '/css/test.styl')
+ .define('embedurl', stylus.url({ paths: [__dirname + '/public'] }))
+ .render(function(err, css){
+ // render it
+ });
+```
- });
+Since base64 encoding an image actually increases the original size, you have the option to use `utf8` encoding when inlining SVG's.
+
+```stylus
+.embed-with-utf8 {
+ background-image: embedurl("circle.svg", "utf8");
+}
+```
## Options
- - `limit` bytesize limit defaulting to 30Kb (30000), use `false` to disable the limit
- - `paths` image resolution path(s)
+- `limit` bytesize limit defaulting to 30Kb (30000), use `false` to disable the limit
+- `paths` image resolution path(s)
View
@@ -35,6 +35,14 @@ var defaultMimes = {
};
/**
+ * Supported encoding types
+ */
+var encodingTypes = {
+ BASE_64: 'base64',
+ UTF8: 'charset=UTF-8'
+}
+
+/**
* Return a url() function with the given `options`.
*
* Options:
@@ -60,14 +68,27 @@ module.exports = function(options) {
var _paths = options.paths || [];
var sizeLimit = null != options.limit ? options.limit : 30000;
var mimes = options.mimes || defaultMimes;
-
- function fn(url){
+ var encoding = encodingTypes.BASE_64;
+
+ /**
+ * @param {object} url - The path to the image you want to encode.
+ * @param {object} enc - The encoding for the image. Defaults to base64, the
+ * other valid option is `utf8`.
+ */
+ function fn(url, enc){
// Compile the url
var compiler = new Compiler(url);
compiler.isURL = true;
url = url.nodes.map(function(node){
return compiler.visit(node);
}).join('');
+
+ // allow for the user to choose the encoding type
+ if( enc ){
+ enc = enc.nodes.map(function(node){
+ return compiler.visit(node);
+ }).join('');
+ }
// Parse literal
url = parse(url);
@@ -76,7 +97,8 @@ module.exports = function(options) {
, hash = url.hash || ''
, literal = new nodes.Literal('url("' + url.href + '")')
, paths = _paths.concat(this.paths)
- , buf;
+ , buf
+ , result;
// Not supported
if (!mime) return literal;
@@ -96,15 +118,23 @@ module.exports = function(options) {
return literal;
}
-
+
// Read data
buf = fs.readFileSync(found);
-
+
// Too large
if (false !== sizeLimit && buf.length > sizeLimit) return literal;
-
+
+ if( enc && enc.toLowerCase() == 'utf8' ){
+ encoding = encodingTypes.UTF8;
+
+ result = encodeURI( buf.toString('utf8') );
+ }else{
+ result = buf.toString(encoding) + hash;
+ }
+
// Encode
- return new nodes.Literal('url("data:' + mime + ';base64,' + buf.toString('base64') + hash + '")');
+ return new nodes.Literal('url("data:' + mime + ';' + encoding + ',' + result + '")');
};
fn.raw = true;
View
4 test/cases/functions.url.css 100644 → 100755
@@ -6,6 +6,10 @@
color: #c00;
background: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTIwIiBoZWlnaHQ9IjEyMCIgdmlld1BvcnQ9IjAgMCAxMjAgMTIwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgICA8Y2lyY2xlIGN4PSI2MCIgY3k9IjYwIiByPSI1MCIvPgo8L3N2Zz4K#some-id");
}
+.embed-with-utf8 {
+ color: #c00;
+ background: url("data:image/svg+xml;charset=UTF-8,%3C?xml%20version=%221.0%22%20encoding=%22utf-8%22?%3E%0A%3Csvg%20width=%22120%22%20height=%22120%22%20viewPort=%220%200%20120%20120%22%20version=%221.1%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%0A%20%20%20%20%3Ccircle%20cx=%2260%22%20cy=%2260%22%20r=%2250%22/%3E%0A%3C/svg%3E%0A");
+}
.too-big-no-hash {
color: #c00;
background: url("tiger.svg");
View
13 test/cases/functions.url.styl 100644 → 100755
@@ -1,19 +1,24 @@
.embed-no-hash {
color: #c00;
- background: url("circle.svg");
+ background: embedurl("circle.svg");
}
.embed-with-hash {
color: #c00;
- background: url("circle.svg#some-id");
+ background: embedurl("circle.svg#some-id");
+}
+
+.embed-with-utf8 {
+ color: #c00;
+ background: embedurl("circle.svg", "utf8");
}
.too-big-no-hash {
color: #c00;
- background: url("tiger.svg");
+ background: embedurl("tiger.svg");
}
.too-big-with-hash {
color: #c00;
- background: url("tiger.svg#some-id");
+ background: embedurl("tiger.svg#some-id");
}
@@ -1,3 +1,3 @@
-test/deps-resolver/index/index.styl
test/deps-resolver/index/a.styl
test/deps-resolver/index/b.styl
+test/deps-resolver/index/index.styl
@@ -1 +1 @@
-@import 'index'
+@import 'index/*'
View
5 test/run.js 100644 → 100755
@@ -4,7 +4,8 @@
*/
var stylus = require('../')
- , fs = require('fs');
+ , fs = require('fs')
+ , should = require('should');
// integration cases
@@ -16,7 +17,7 @@ addSuite('integration', readDir('test/cases'), function(test){
.set('filename', path)
.include(__dirname + '/images')
.include(__dirname + '/cases/import.basic')
- .define('url', stylus.url());
+ .define('embedurl', stylus.url());
if (~test.indexOf('compress')) style.set('compress', true);
if (~test.indexOf('include')) style.set('include css', true);

0 comments on commit 7ad33ab

Please sign in to comment.