Alexander Alexander - 4 months ago 26
CSS Question

Compass inline-image syntax/configuration

I add the following block to

myapp.scss
:

.resourceType2 {
background: url('../resources/ressource2.png') no-repeat 2px 1px;
padding-left: 16px;
}


After I call
sencha app build production
with Cmd 6.0.1.76, I see the background-image. I found that you can use
inline-image
and compass should make css inline images from your images. So I add to
myapp.scss
instead:

.resourceType2 {
background: inline-image('../resources/ressource2.png') no-repeat 2px 1px;
padding-left: 16px;
}


After successful build, I don't see the images.

I found that
MyApp-all.css
still contains
inline-image('../resources/ressource2.png')
, just as if it wouldn't replace them properly. Am I missing some config option required to enable inline-image generation?

Answer

While reading the SenchaCon roadshow agenda, I more or less stumbled upon the answer.

Summary:

Cmd 6.0.1 does not use sass or compass any longer. It uses Sencha Fashion, which takes sass files and compiles them. Sencha Fashion does have support for sass variables, but not for compass helpers written in Ruby, because the goal was to remove the Ruby dependency. Instead, one would have to rewrite the required helpers as Sencha Fashion extensions in JavaScript.

I have yet to find a list of available/builtin "extensions" and a full guide how to write my own. There are no javascript extensions available in the ext package as of now. There is no documentation available with all builtin SASS functions and their parameters, you can only find them by searching through the original scss files delivered with ExtJS.

Extension example:

If you want to have an extension that converts resource images to their data uri equivalent, you could put the following code into your sass/src directory, e.g. as inlineimage.js:

exports.init = function(runtime) {
    if (typeof String.prototype.endsWith !== 'function') {
        String.prototype.endsWith = function(suffix) { 
            return this.indexOf(suffix, this.length - ((suffix && suffix.length) || 0)) !== -1; 
        };
    }
    function _arrayBufferToBase64( buffer ) {
        var binary = '';
        var bytes = new Uint8Array( buffer );
        var len = bytes.byteLength;
        for (var i = 0; i < len; i++) {
            binary += String.fromCharCode( bytes[ i ] );
        }
        return window.btoa( binary );
    }
    runtime.register({
        inlineImage: function (uri, mime) {
            // URI has the keys: value,unit,quoteChar,splat
            // URI has the values: ../../resources/delete.gif,,',
            if(!mime) {
                if(uri.value.toLowerCase().endsWith(".png")) mime = "image/png";
                else if(uri.value.toLowerCase().endsWith(".gif")) mime = "image/gif";
                else if(uri.value.toLowerCase().endsWith(".jpg")) mime = "image/jpeg";
                else if(uri.value.toLowerCase().endsWith(".jpeg")) mime = "image/jpeg";
            }
            var xhr = new XMLHttpRequest();
            xhr.open('GET', uri.value, false); 
            xhr.responseType = "arraybuffer";
            xhr.send(null);
            if(xhr.status==404) throw new Error("Inline image source " + uri.value + " not found");
            uri.value="url(data:"+mime+";base64,"+_arrayBufferToBase64(xhr.response)+")";
            uri.quoteChar="";
            return uri;
        }
    });
};

In your scss file, for instance sass/src/view/Viewport.scss, you would then write:

require("../inlineimage.js");
.icon-checklist {
    background: inlineImage('../images/checklist.png') no-repeat center center !important;
}

The image in this case would be located in sass/images, so that cmd won't copy it into the output resource folder (it should only show up in the output CSS file).

The inlineImage in the scss file now refers to the registered javascript function inlineImage, which will be executed to download the image and return it as a data uri.

Sources: