Modules (188)

ExtensionUtils

Description

ExtensionUtils defines utility methods for implementing extensions.

Dependencies

Functions

Public API

addEmbeddedStyleSheet

Appends a <style> tag to the document's head.

css non-nullable string
CSS code to use as the tag's content
Returns: !HTMLStyleElement
The generated HTML node
    function addEmbeddedStyleSheet(css) {
        return $("<style>").text(css).appendTo("head")[0];
    }
Public API

addLinkedStyleSheet

Appends a <link> tag to the document's head.

url non-nullable string
URL to a style sheet
deferred optional $.Deferred
Optionally check for load and error events
Returns: !HTMLLinkElement
The generated HTML node
    function addLinkedStyleSheet(url, deferred) {
        var attributes = {
            type: "text/css",
            rel:  "stylesheet",
            href: url
        };

        var $link = $("<link/>").attr(attributes);

        if (deferred) {
            $link.on('load', deferred.resolve).on('error', deferred.reject);
        }

        $link.appendTo("head");

        return $link[0];
    }
Public API

getModulePath

Returns a path to an extension module.

module non-nullable module
Module provided by RequireJS
path nullable string
Relative path from the extension folder to a file
Returns: !string
The path to the module's folder
    function getModulePath(module, path) {
        var modulePath = module.uri.substr(0, module.uri.lastIndexOf("/") + 1);
        if (path) {
            modulePath += path;
        }

        return modulePath;
    }
Public API

getModuleUrl

Returns a URL to an extension module.

module non-nullable module
Module provided by RequireJS
path nullable string
Relative path from the extension folder to a file
Returns: !string
The URL to the module's folder
    function getModuleUrl(module, path) {
        var url = encodeURI(getModulePath(module, path));

        // On Windows, $.get() fails if the url is a full pathname. To work around this,
        // prepend "file:///". On the Mac, $.get() works fine if the url is a full pathname,
        // but *doesn't* work if it is prepended with "file://". Go figure.
        // However, the prefix "file://localhost" does work.
        if (brackets.platform === "win" && url.indexOf(":") !== -1) {
            url = "file:///" + url;
        }

        return url;
    }

isAbsolutePathOrUrl

getModuleUrl returns different urls for win platform so that's why we need a different check here

pathOrUrl non-nullable string
that should be checked if it's absolute
Returns: !boolean
returns true if pathOrUrl is absolute url on win platform or when it's absolute path on other platforms
See
getModuleUrl
    function isAbsolutePathOrUrl(pathOrUrl) {
        return brackets.platform === "win" ? PathUtils.isAbsoluteUrl(pathOrUrl) : FileSystem.isAbsolutePath(pathOrUrl);
    }
Public API

loadFile

Performs a GET request using a path relative to an extension module.

The resulting URL can be retrieved in the resolve callback by accessing

module non-nullable module
Module provided by RequireJS
path non-nullable string
Relative path from the extension folder to a file
Returns: !$.Promise
A promise object that is resolved with the contents of the requested file
    function loadFile(module, path) {
        var url     = PathUtils.isAbsoluteUrl(path) ? path : getModuleUrl(module, path),
            promise = $.get(url);

        return promise;
    }
Public API

loadMetadata

Loads the package.json file in the given extension folder as well as any additional metadata.

If there's a .disabled file in the extension directory, then the content of package.json will be augmented with disabled property set to true. It will override whatever value of disabled might be set.

folder string
The extension folder.
Returns: $.Promise
A promise object that is resolved with the parsed contents of the package.json file, or rejected if there is no package.json with the boolean indicating whether .disabled file exists.
    function loadMetadata(folder) {
        var packageJSONFile = FileSystem.getFileForPath(folder + "/package.json"),
            disabledFile = FileSystem.getFileForPath(folder + "/.disabled"),
            baseName = FileUtils.getBaseName(folder),
            result = new $.Deferred(),
            jsonPromise = new $.Deferred(),
            disabledPromise = new $.Deferred(),
            json,
            disabled;
        FileUtils.readAsText(packageJSONFile)
            .then(function (text) {
                try {
                    json = JSON.parse(text);
                    jsonPromise.resolve();
                } catch (e) {
                    jsonPromise.reject();
                }
            })
            .fail(jsonPromise.reject);
        disabledFile.exists(function (err, exists) {
            if (err) {
                disabled = false;
            } else {
                disabled = exists;
            }

            var defaultDisabled = PreferencesManager.get("extensions.default.disabled");
            if (Array.isArray(defaultDisabled) && defaultDisabled.indexOf(folder) !== -1) {
                console.warn("Default extension has been disabled on startup: " + baseName);
                disabled = true;
            }

            disabledPromise.resolve();
        });
        Async.waitForAll([jsonPromise, disabledPromise])
            .always(function () {
                if (!json) {
                    // if we don't have any metadata for the extension
                    // we should still create an empty one, so we can attach
                    // disabled property on it in case it's disabled
                    json = {
                        name: baseName
                    };
                }
                json.disabled = disabled;
                result.resolve(json);
            });
        return result.promise();
    }

    exports.addEmbeddedStyleSheet = addEmbeddedStyleSheet;
    exports.addLinkedStyleSheet   = addLinkedStyleSheet;
    exports.parseLessCode         = parseLessCode;
    exports.getModulePath         = getModulePath;
    exports.getModuleUrl          = getModuleUrl;
    exports.loadFile              = loadFile;
    exports.loadStyleSheet        = loadStyleSheet;
    exports.loadMetadata          = loadMetadata;
});
Public API

loadStyleSheet

Loads a style sheet (CSS or LESS) relative to the extension module.

module non-nullable module
Module provided by RequireJS
path non-nullable string
Relative path from the extension folder to a CSS or LESS file
Returns: !$.Promise
A promise object that is resolved with an HTML node if the file can be loaded.
    function loadStyleSheet(module, path) {
        var result = new $.Deferred();

        loadFile(module, path)
            .done(function (content) {
                var url = this.url;

                if (url.slice(-5) === ".less") {
                    parseLessCode(content, url)
                        .done(function (css) {
                            result.resolve(addEmbeddedStyleSheet(css));
                        })
                        .fail(result.reject);
                } else {
                    var deferred = new $.Deferred(),
                        link = addLinkedStyleSheet(url, deferred);

                    deferred
                        .done(function () {
                            result.resolve(link);
                        })
                        .fail(result.reject);
                }
            })
            .fail(result.reject);

        // Summarize error info to console for easier debugging
        result.fail(function (error, textStatus, httpError) {
            if (error.readyState !== undefined) {
                // If first arg is a jQXHR object, the real error info is in the next two args
                console.error("[Extension] Unable to read stylesheet " + path + ":", textStatus, httpError);
            } else {
                console.error("[Extension] Unable to process stylesheet " + path, error);
            }
        });

        return result.promise();
    }
Public API

parseLessCode

Parses LESS code and returns a promise that resolves with plain CSS code.

Pass the <a href="">url</a> argument to resolve relative URLs contained in the code. Make sure URLs in the code are wrapped in quotes, like so: background-image: url("image.png");

code non-nullable string
LESS code to parse
url nullable string
URL to the file containing the code
Returns: !$.Promise
A promise object that is resolved with CSS code if the LESS code can be parsed
    function parseLessCode(code, url) {
        var result = new $.Deferred(),
            options;

        if (url) {
            var dir = url.slice(0, url.lastIndexOf("/") + 1);

            options = {
                filename: url,
                rootpath: dir
            };

            if (isAbsolutePathOrUrl(url)) {
                options.currentFileInfo = {
                    currentDirectory: dir,
                    entryPath: dir,
                    filename: url,
                    rootFilename: url,
                    rootpath: dir
                };
            }
        }

        less.render(code, options, function onParse(err, tree) {
            if (err) {
                result.reject(err);
            } else {
                result.resolve(tree.css);
            }
        });

        return result.promise();
    }