ExtensionUtils defines utility methods for implementing extensions.
Appends a <style> tag to the document's head.
function addEmbeddedStyleSheet(css) {
return $("<style>").text(css).appendTo("head")[0];
}
Appends a <link> tag to the document's head.
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];
}
Returns a path to an extension module.
function getModulePath(module, path) {
var modulePath = module.uri.substr(0, module.uri.lastIndexOf("/") + 1);
if (path) {
modulePath += path;
}
return modulePath;
}
Returns a URL to an extension module.
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;
}
getModuleUrl returns different urls for win platform so that's why we need a different check here
function isAbsolutePathOrUrl(pathOrUrl) {
return brackets.platform === "win" ? PathUtils.isAbsoluteUrl(pathOrUrl) : FileSystem.isAbsolutePath(pathOrUrl);
}
Performs a GET request using a path relative to an extension module.
The resulting URL can be retrieved in the resolve callback by accessing
function loadFile(module, path) {
var url = PathUtils.isAbsoluteUrl(path) ? path : getModuleUrl(module, path),
promise = $.get(url);
return promise;
}
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.
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;
});
Loads a style sheet (CSS or LESS) relative to the extension module.
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();
}
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");
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();
}