Skip to content
Browse files

merge package.json

  • Loading branch information...
2 parents 3efd03d + 318bec2 commit c6fc7f118bf5d1da4e205bb6f41178e8af354f65 @theoreticaLee theoreticaLee committed
View
4 package.json
@@ -1,7 +1,7 @@
{
"name": "Brackets",
- "version": "0.22.0-0",
- "apiVersion": "0.22.0",
+ "version": "0.23.0-0",
+ "apiVersion": "0.23.0",
"homepage": "http://brackets.io",
"issues": {
"url": "http://github.com/adobe/brackets/issues"
View
38 src/LiveDevelopment/Documents/HTMLDocument.js
@@ -44,9 +44,10 @@
define(function HTMLDocumentModule(require, exports, module) {
"use strict";
- var Inspector = require("LiveDevelopment/Inspector/Inspector");
- var DOMAgent = require("LiveDevelopment/Agents/DOMAgent");
- var HighlightAgent = require("LiveDevelopment/Agents/HighlightAgent");
+ var DOMAgent = require("LiveDevelopment/Agents/DOMAgent"),
+ HighlightAgent = require("LiveDevelopment/Agents/HighlightAgent"),
+ Inspector = require("LiveDevelopment/Inspector/Inspector"),
+ LiveDevelopment = require("LiveDevelopment/LiveDevelopment");
/** Constructor
*
@@ -58,13 +59,21 @@ define(function HTMLDocumentModule(require, exports, module) {
}
this.doc = doc;
this.editor = editor;
- this.onHighlight = this.onHighlight.bind(this);
- this.onChange = this.onChange.bind(this);
+
this.onCursorActivity = this.onCursorActivity.bind(this);
- $(HighlightAgent).on("highlight", this.onHighlight);
- $(this.editor).on("change", this.onChange);
$(this.editor).on("cursorActivity", this.onCursorActivity);
this.onCursorActivity();
+
+ // Experimental code
+ if (LiveDevelopment.config.experimental) {
+
+ // Used by highlight agent to highlight editor text as selected in browser
+ this.onHighlight = this.onHighlight.bind(this);
+ $(HighlightAgent).on("highlight", this.onHighlight);
+
+ this.onChange = this.onChange.bind(this);
+ $(this.editor).on("change", this.onChange);
+ }
};
/** Close the document */
@@ -72,10 +81,17 @@ define(function HTMLDocumentModule(require, exports, module) {
if (!this.editor) {
return;
}
- $(HighlightAgent).off("highlight", this.onHighlight);
- $(this.editor).off("change", this.onChange);
+
$(this.editor).off("cursorActivity", this.onCursorActivity);
- this.onHighlight();
+
+ // Experimental code
+ if (LiveDevelopment.config.experimental) {
+
+ $(HighlightAgent).off("highlight", this.onHighlight);
+ this.onHighlight();
+
+ $(this.editor).off("change", this.onChange);
+ }
};
@@ -84,7 +100,7 @@ define(function HTMLDocumentModule(require, exports, module) {
/** Triggered on cursor activity by the editor */
HTMLDocument.prototype.onCursorActivity = function onCursorActivity(event, editor) {
var codeMirror = this.editor._codeMirror;
- if (Inspector.config.highlight) {
+ if (LiveDevelopment.config.experimental && Inspector.config.highlight) {
var location = codeMirror.indexFromPos(codeMirror.getCursor());
var node = DOMAgent.allNodesAtLocation(location).pop();
HighlightAgent.node(node);
View
2 src/LiveDevelopment/LiveDevelopment.js
@@ -228,7 +228,7 @@ define(function LiveDevelopment(require, exports, module) {
return exports.config.experimental ? JSDocument : null;
}
- if (exports.config.experimental && _isHtmlFileExt(doc.extension)) {
+ if (_isHtmlFileExt(doc.extension)) {
return HTMLDocument;
}
View
4 src/config.json
@@ -15,8 +15,8 @@
"contributors_url": "https://api.github.com/repos/adobe/brackets/contributors"
},
"name": "Brackets",
- "version": "0.22.0-0",
- "apiVersion": "0.22.0",
+ "version": "0.23.0-0",
+ "apiVersion": "0.23.0",
"homepage": "http://brackets.io",
"issues": {
"url": "http://github.com/adobe/brackets/issues"
View
5 src/extensibility/Package.js
@@ -78,14 +78,15 @@ define(function (require, exports, module) {
* if there are errors or null if the extension did not include package.json.
*
* @param {string} Absolute path to the package zip file
+ * @param {{requirePackageJSON: ?boolean}} validation options
* @return {$.Promise} A promise that is resolved with information about the package
*/
- function validate(path) {
+ function validate(path, options) {
var d = new $.Deferred();
_nodeConnectionDeferred
.done(function (nodeConnection) {
if (nodeConnection.connected()) {
- nodeConnection.domains.extensionManager.validate(path)
+ nodeConnection.domains.extensionManager.validate(path, options)
.done(function (result) {
d.resolve({
errors: result.errors,
View
189 src/extensibility/node/ExtensionManagerDomain.js
@@ -27,25 +27,18 @@ indent: 4, maxerr: 50 */
"use strict";
-var unzip = require("unzip"),
- semver = require("semver"),
- path = require("path"),
- http = require("http"),
- request = require("request"),
- os = require("os"),
- fs = require("fs-extra");
+var unzip = require("unzip"),
+ semver = require("semver"),
+ path = require("path"),
+ http = require("http"),
+ request = require("request"),
+ os = require("os"),
+ fs = require("fs-extra"),
+ validate = require("./package-validator").validate;
var Errors = {
- NOT_FOUND_ERR: "NOT_FOUND_ERR", // {0} is path where ZIP file was expected
- INVALID_ZIP_FILE: "INVALID_ZIP_FILE", // {0} is path to ZIP file
- INVALID_PACKAGE_JSON: "INVALID_PACKAGE_JSON", // {0} is JSON parse error, {1} is path to ZIP file
- MISSING_PACKAGE_NAME: "MISSING_PACKAGE_NAME", // {0} is path to ZIP file
- BAD_PACKAGE_NAME: "BAD_PACKAGE_NAME", // {0} is the name
- MISSING_PACKAGE_VERSION: "MISSING_PACKAGE_VERSION", // {0} is path to ZIP file
- INVALID_VERSION_NUMBER: "INVALID_VERSION_NUMBER", // {0} is version string in JSON, {1} is path to ZIP file
API_NOT_COMPATIBLE: "API_NOT_COMPATIBLE",
- MISSING_MAIN: "MISSING_MAIN", // {0} is path to ZIP file
MISSING_REQUIRED_OPTIONS: "MISSING_REQUIRED_OPTIONS",
ALREADY_INSTALLED: "ALREADY_INSTALLED",
DOWNLOAD_ID_IN_USE: "DOWNLOAD_ID_IN_USE",
@@ -62,162 +55,6 @@ var Errors = {
*/
var pendingDownloads = {};
-/**
- * Returns true if the name presented is acceptable as a package name. This enforces the
- * requirement as presented in the CommonJS spec: http://wiki.commonjs.org/wiki/Packages/1.0
- *
- * @param {string} Name to test
- * @return {boolean} true if the name is valid
- */
-function validateName(name) {
- // "This must be a unique, lowercase alpha-numeric name without spaces. It may include "." or "_" or "-" characters."
- if (/^[a-z0-9._\-]+$/.exec(name)) {
- return true;
- }
- return false;
-}
-
-/**
- * Implements the "validate" command in the "extensions" domain.
- * Validates the zipped package at path.
- *
- * The "err" parameter of the callback is only set if there was an
- * unexpected error. Otherwise, errors are reported in the result.
- *
- * The result object has an "errors" property. It is an array of
- * arrays of strings. Each array in the array is a set of parameters
- * that can be passed to StringUtils.format for internationalization.
- * The array will be empty if there are no errors.
- *
- * The result will have a "metadata" property if the metadata was
- * read successfully from package.json in the zip file.
- *
- * @param {string} Absolute path to the package zip file
- * @param {function} callback (err, result)
- */
-function _cmdValidate(path, callback) {
- fs.exists(path, function (doesExist) {
- if (!doesExist) {
- callback(null, {
- errors: [[Errors.NOT_FOUND_ERR, path]]
- });
- return;
- }
- var callbackCalled = false;
- var metadata;
- var foundMainIn = null;
- var errors = [];
- var commonPrefix = null;
-
- var readStream = fs.createReadStream(path);
-
- readStream
- .pipe(unzip.Parse())
- .on("error", function (exception) {
- // General error to report for problems reading the file
- errors.push([Errors.INVALID_ZIP_FILE, path]);
- callback(null, {
- errors: errors
- });
- callbackCalled = true;
- readStream.destroy();
- })
- .on("entry", function (entry) {
- // look for the metadata
- var fileName = entry.path;
-
- var slash = fileName.indexOf("/");
- if (slash > -1) {
- var prefix = fileName.substring(0, slash);
- if (commonPrefix === null) {
- commonPrefix = prefix;
- } else if (prefix !== commonPrefix) {
- commonPrefix = "";
- }
- if (commonPrefix) {
- fileName = fileName.substring(commonPrefix.length + 1);
- }
- } else {
- commonPrefix = "";
- }
-
- if (fileName === "package.json") {
- // This handles an edge case where we found a package.json in a
- // nested directory that we thought was a commonPrefix but
- // actually wasn't. We reset as if we never read that first
- // package.json
- if (metadata) {
- metadata = undefined;
- errors = [];
- }
-
- var packageJSON = "";
- entry
- .on("data", function (data) {
- // We're assuming utf8 encoding here, which is pretty safe
- // Note that I found that .setEncoding on the stream
- // would fail, so I convert the buffer to a string here.
- packageJSON += data.toString("utf8");
- })
- .on("error", function (exception) {
- // general exception handler. It is unknown what kinds of
- // errors we can get here.
- callback(exception, null);
- callbackCalled = true;
- readStream.destroy();
- })
- .on("end", function () {
- // attempt to parse the metadata
- try {
- metadata = JSON.parse(packageJSON);
- } catch (e) {
- errors.push([Errors.INVALID_PACKAGE_JSON, e.toString(), path]);
- return;
- }
-
- // confirm required fields in the metadata
- if (!metadata.name) {
- errors.push([Errors.MISSING_PACKAGE_NAME, path]);
- } else if (!validateName(metadata.name)) {
- errors.push([Errors.BAD_PACKAGE_NAME, metadata.name]);
- }
- if (!metadata.version) {
- errors.push([Errors.MISSING_PACKAGE_VERSION, path]);
- } else if (!semver.valid(metadata.version)) {
- errors.push([Errors.INVALID_VERSION_NUMBER, metadata.version, path]);
- }
- });
- } else if (fileName === "main.js") {
- foundMainIn = commonPrefix;
- }
- })
- .on("end", function () {
- // Reached the end of the zipfile
- // Report results
-
- // generally, if we hit an exception, we've already called the callback
- if (callbackCalled) {
- return;
- }
-
- if (foundMainIn === null || foundMainIn !== commonPrefix) {
- errors.push([Errors.MISSING_MAIN, path]);
- }
-
- // No errors and no metadata means that we never found the metadata
- if (errors.length === 0 && !metadata) {
- metadata = null;
- }
-
- callback(null, {
- errors: errors,
- metadata: metadata,
- commonPrefix: commonPrefix
- });
- });
- });
-}
-
/**
* Private function to unzip to the correct directory.
@@ -387,7 +224,7 @@ function _cmdInstall(packagePath, destinationDirectory, options, callback) {
}
};
- _cmdValidate(packagePath, validateCallback);
+ validate(packagePath, {}, validateCallback);
}
@@ -511,13 +348,17 @@ function init(domainManager) {
domainManager.registerCommand(
"extensionManager",
"validate",
- _cmdValidate,
+ validate,
true,
"Verifies that the contents of the given ZIP file are a valid Brackets extension package",
[{
name: "path",
type: "string",
description: "absolute filesystem path of the extension package"
+ }, {
+ name: "options",
+ type: "{requirePackageJSON: ?boolean}",
+ description: "options to control the behavior of the validator"
}],
[{
name: "errors",
@@ -609,7 +450,7 @@ function init(domainManager) {
}
// used in unit tests
-exports._cmdValidate = _cmdValidate;
+exports._cmdValidate = validate;
exports._cmdInstall = _cmdInstall;
// used to load the domain
View
3 src/extensibility/node/README.md
@@ -0,0 +1,3 @@
+## Brackets Extensibility
+
+This code is used by Brackets to implement its extension management features. It is likely not useful to anyone not working with Brackets extensions.
View
214 src/extensibility/node/package-validator.js
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+/*jslint vars: true, plusplus: true, devel: true, node: true, nomen: true,
+indent: 4, maxerr: 50 */
+
+"use strict";
+
+var unzip = require("unzip"),
+ semver = require("semver"),
+ path = require("path"),
+ http = require("http"),
+ request = require("request"),
+ os = require("os"),
+ fs = require("fs-extra");
+
+
+var Errors = {
+ NOT_FOUND_ERR: "NOT_FOUND_ERR", // {0} is path where ZIP file was expected
+ INVALID_ZIP_FILE: "INVALID_ZIP_FILE", // {0} is path to ZIP file
+ INVALID_PACKAGE_JSON: "INVALID_PACKAGE_JSON", // {0} is JSON parse error, {1} is path to ZIP file
+ MISSING_PACKAGE_NAME: "MISSING_PACKAGE_NAME", // {0} is path to ZIP file
+ BAD_PACKAGE_NAME: "BAD_PACKAGE_NAME", // {0} is the name
+ MISSING_PACKAGE_VERSION: "MISSING_PACKAGE_VERSION", // {0} is path to ZIP file
+ INVALID_VERSION_NUMBER: "INVALID_VERSION_NUMBER", // {0} is version string in JSON, {1} is path to ZIP file
+ MISSING_MAIN: "MISSING_MAIN", // {0} is path to ZIP file
+ MISSING_PACKAGE_JSON: "MISSING_PACKAGE_JSON" // {0} is path to ZIP file
+};
+
+/**
+ * Returns true if the name presented is acceptable as a package name. This enforces the
+ * requirement as presented in the CommonJS spec: http://wiki.commonjs.org/wiki/Packages/1.0
+ *
+ * @param {string} Name to test
+ * @return {boolean} true if the name is valid
+ */
+function validateName(name) {
+ // "This must be a unique, lowercase alpha-numeric name without spaces. It may include "." or "_" or "-" characters."
+ if (/^[a-z0-9._\-]+$/.exec(name)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Implements the "validate" command in the "extensions" domain.
+ * Validates the zipped package at path.
+ *
+ * The "err" parameter of the callback is only set if there was an
+ * unexpected error. Otherwise, errors are reported in the result.
+ *
+ * The result object has an "errors" property. It is an array of
+ * arrays of strings. Each array in the array is a set of parameters
+ * that can be passed to StringUtils.format for internationalization.
+ * The array will be empty if there are no errors.
+ *
+ * The result will have a "metadata" property if the metadata was
+ * read successfully from package.json in the zip file.
+ *
+ * @param {string} Absolute path to the package zip file
+ * @param {{requirePackageJSON: ?boolean}} validation options
+ * @param {function} callback (err, result)
+ */
+function validate(path, options, callback) {
+ options = options || {};
+ fs.exists(path, function (doesExist) {
+ if (!doesExist) {
+ callback(null, {
+ errors: [[Errors.NOT_FOUND_ERR, path]]
+ });
+ return;
+ }
+ var callbackCalled = false;
+ var metadata;
+ var foundMainIn = null;
+ var errors = [];
+ var commonPrefix = null;
+
+ var readStream = fs.createReadStream(path);
+
+ readStream
+ .pipe(unzip.Parse())
+ .on("error", function (exception) {
+ // General error to report for problems reading the file
+ errors.push([Errors.INVALID_ZIP_FILE, path]);
+ callback(null, {
+ errors: errors
+ });
+ callbackCalled = true;
+ readStream.destroy();
+ })
+ .on("entry", function (entry) {
+ // look for the metadata
+ var fileName = entry.path;
+
+ var slash = fileName.indexOf("/");
+ if (slash > -1) {
+ var prefix = fileName.substring(0, slash);
+ if (commonPrefix === null) {
+ commonPrefix = prefix;
+ } else if (prefix !== commonPrefix) {
+ commonPrefix = "";
+ }
+ if (commonPrefix) {
+ fileName = fileName.substring(commonPrefix.length + 1);
+ }
+ } else {
+ commonPrefix = "";
+ }
+
+ if (fileName === "package.json") {
+ // This handles an edge case where we found a package.json in a
+ // nested directory that we thought was a commonPrefix but
+ // actually wasn't. We reset as if we never read that first
+ // package.json
+ if (metadata) {
+ metadata = undefined;
+ errors = [];
+ }
+
+ var packageJSON = "";
+ entry
+ .on("data", function (data) {
+ // We're assuming utf8 encoding here, which is pretty safe
+ // Note that I found that .setEncoding on the stream
+ // would fail, so I convert the buffer to a string here.
+ packageJSON += data.toString("utf8");
+ })
+ .on("error", function (exception) {
+ // general exception handler. It is unknown what kinds of
+ // errors we can get here.
+ callback(exception, null);
+ callbackCalled = true;
+ readStream.destroy();
+ })
+ .on("end", function () {
+ // attempt to parse the metadata
+ try {
+ metadata = JSON.parse(packageJSON);
+ } catch (e) {
+ errors.push([Errors.INVALID_PACKAGE_JSON, e.toString(), path]);
+ return;
+ }
+
+ // confirm required fields in the metadata
+ if (!metadata.name) {
+ errors.push([Errors.MISSING_PACKAGE_NAME, path]);
+ } else if (!validateName(metadata.name)) {
+ errors.push([Errors.BAD_PACKAGE_NAME, metadata.name]);
+ }
+ if (!metadata.version) {
+ errors.push([Errors.MISSING_PACKAGE_VERSION, path]);
+ } else if (!semver.valid(metadata.version)) {
+ errors.push([Errors.INVALID_VERSION_NUMBER, metadata.version, path]);
+ }
+ });
+ } else if (fileName === "main.js") {
+ foundMainIn = commonPrefix;
+ }
+ })
+ .on("end", function () {
+ // Reached the end of the zipfile
+ // Report results
+
+ // generally, if we hit an exception, we've already called the callback
+ if (callbackCalled) {
+ return;
+ }
+
+ if (foundMainIn === null || foundMainIn !== commonPrefix) {
+ errors.push([Errors.MISSING_MAIN, path]);
+ }
+
+ // No errors and no metadata means that we never found the metadata
+ if (errors.length === 0 && !metadata) {
+ metadata = null;
+ }
+
+ if (metadata === null && options.requirePackageJSON) {
+ errors.push([Errors.MISSING_PACKAGE_JSON, path]);
+ }
+
+ callback(null, {
+ errors: errors,
+ metadata: metadata,
+ commonPrefix: commonPrefix
+ });
+ });
+ });
+}
+
+exports.errors = Errors;
+exports.validate = validate;
View
2 src/extensibility/node/package.json
@@ -1,5 +1,7 @@
{
"name": "brackets-extensibility",
+ "description": "Used in the management of Brackets extensions",
+ "version": "0.23.0",
"dependencies": {
"unzip": "0.1.x",
"semver": ">1.1.0 <2.0.0",
View
38 src/extensibility/node/spec/Validation.spec.js
@@ -28,7 +28,7 @@ indent: 4, maxerr: 50 */
"use strict";
-var ExtensionsDomain = require("../ExtensionManagerDomain"),
+var packageValidator = require("../package-validator"),
path = require("path");
var testFilesDirectory = path.join(path.dirname(module.filename),
@@ -54,7 +54,7 @@ var basicValidExtension = path.join(testFilesDirectory, "basic-valid-extension.z
describe("Package Validation", function () {
it("should handle a good package", function (done) {
- ExtensionsDomain._cmdValidate(basicValidExtension, function (err, result) {
+ packageValidator.validate(basicValidExtension, {}, function (err, result) {
expect(err).toBeNull();
expect(result.errors.length).toEqual(0);
var metadata = result.metadata;
@@ -66,7 +66,7 @@ describe("Package Validation", function () {
});
it("should NOT complain about missing package.json", function (done) {
- ExtensionsDomain._cmdValidate(missingPackageJSON, function (err, result) {
+ packageValidator.validate(missingPackageJSON, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(0);
@@ -75,8 +75,20 @@ describe("Package Validation", function () {
});
});
+ it("should complain about missing package.json if you tell it to", function (done) {
+ packageValidator.validate(missingPackageJSON, {
+ requirePackageJSON: true
+ }, function (err, result) {
+ expect(err).toBeNull();
+ var errors = result.errors;
+ expect(errors.length).toEqual(1);
+ expect(errors[0][0]).toEqual("MISSING_PACKAGE_JSON");
+ done();
+ });
+ });
+
it("should complain about illegal path", function (done) {
- ExtensionsDomain._cmdValidate(path.join(testFilesDirectory, "NO_FILE_HERE"), function (err, result) {
+ packageValidator.validate(path.join(testFilesDirectory, "NO_FILE_HERE"), {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(1);
@@ -87,7 +99,7 @@ describe("Package Validation", function () {
});
it("should complain about invalid JSON", function (done) {
- ExtensionsDomain._cmdValidate(invalidJSON, function (err, result) {
+ packageValidator.validate(invalidJSON, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(1);
@@ -100,7 +112,7 @@ describe("Package Validation", function () {
});
it("should complain about an invalid zip file", function (done) {
- ExtensionsDomain._cmdValidate(invalidZip, function (err, result) {
+ packageValidator.validate(invalidZip, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(1);
@@ -110,7 +122,7 @@ describe("Package Validation", function () {
});
it("should require name and version in the metadata", function (done) {
- ExtensionsDomain._cmdValidate(missingNameVersion, function (err, result) {
+ packageValidator.validate(missingNameVersion, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(2);
@@ -121,7 +133,7 @@ describe("Package Validation", function () {
});
it("should validate the version number", function (done) {
- ExtensionsDomain._cmdValidate(invalidVersion, function (err, result) {
+ packageValidator.validate(invalidVersion, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(1);
@@ -132,7 +144,7 @@ describe("Package Validation", function () {
});
it("should require a main.js in the zip file", function (done) {
- ExtensionsDomain._cmdValidate(missingMain, function (err, result) {
+ packageValidator.validate(missingMain, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(1);
@@ -142,7 +154,7 @@ describe("Package Validation", function () {
});
it("should determine the common prefix if there is one", function (done) {
- ExtensionsDomain._cmdValidate(oneLevelDown, function (err, result) {
+ packageValidator.validate(oneLevelDown, {}, function (err, result) {
expect(err).toBeNull();
expect(result.errors.length).toEqual(0);
expect(result.metadata.name).toEqual("one-level-extension");
@@ -152,7 +164,7 @@ describe("Package Validation", function () {
});
it("should not be fooled by bogus top directories", function (done) {
- ExtensionsDomain._cmdValidate(bogusTopDir, function (err, result) {
+ packageValidator.validate(bogusTopDir, {}, function (err, result) {
expect(err).toBeNull();
expect(result.errors.length).toEqual(0);
expect(result.metadata.name).toEqual("bogus-top-dir");
@@ -162,7 +174,7 @@ describe("Package Validation", function () {
});
it("should not allow names that contain disallowed characters", function (done) {
- ExtensionsDomain._cmdValidate(badname, function (err, result) {
+ packageValidator.validate(badname, {}, function (err, result) {
expect(err).toBeNull();
expect(result.errors.length).toEqual(1);
expect(result.errors[0][0]).toEqual("BAD_PACKAGE_NAME");
@@ -171,7 +183,7 @@ describe("Package Validation", function () {
});
it("should complain about files that don't have main in the top dir", function (done) {
- ExtensionsDomain._cmdValidate(mainInDirectory, function (err, result) {
+ packageValidator.validate(mainInDirectory, {}, function (err, result) {
expect(err).toBeNull();
var errors = result.errors;
expect(errors.length).toEqual(1);
View
51 src/extensions/default/DebugCommands/main.js
@@ -159,18 +159,13 @@ define(function (require, exports, module) {
NativeFileSystem.requestNativeFileSystem(stringsPath, function (fs) {
fs.root.createReader().readEntries(function (entries) {
- var $activeLanguage,
- $submit,
- locale;
+ var $submit,
+ $select,
+ locale,
+ curLocale = (brackets.isLocaleDefault() ? null : brackets.getLocale());
function setLanguage(event) {
- if ($activeLanguage) {
- $activeLanguage.css("font-weight", "normal");
- }
- $activeLanguage = $(event.currentTarget);
- locale = $activeLanguage.data("locale");
-
- $activeLanguage.css("font-weight", "bold");
+ locale = $select.val();
$submit.attr("disabled", false);
}
@@ -188,8 +183,8 @@ define(function (require, exports, module) {
.text(Strings.LANGUAGE_MESSAGE)
.appendTo($body);
- var $ul = $("<ul>")
- .on("click", "li", setLanguage)
+ $select = $("<select>")
+ .on("change", setLanguage)
.appendTo($p);
var $footer = $("<div class='modal-footer' />")
@@ -205,12 +200,12 @@ define(function (require, exports, module) {
$submit = $("<button class='dialog-button btn primary'>")
.text(Strings.LANGUAGE_SUBMIT)
.on("click", function () {
- if (!$activeLanguage) {
+ if (locale === undefined) {
return;
+ } else if (locale !== curLocale) {
+ brackets.setLocale(locale);
+ CommandManager.execute(DEBUG_REFRESH_WINDOW);
}
- brackets.setLocale(locale);
-
- CommandManager.execute(DEBUG_REFRESH_WINDOW);
})
.attr("disabled", "disabled")
.appendTo($footer);
@@ -225,17 +220,18 @@ define(function (require, exports, module) {
$(this).remove();
});
+ function addLocale(text, val) {
+ var $option = $("<option>")
+ .text(text)
+ .val(val)
+ .appendTo($select);
+ }
+
// add system default
- var $li = $("<li>")
- .text("system default")
- .data("locale", null)
- .appendTo($ul);
+ addLocale(Strings.LANGUAGE_SYSTEM_DEFAULT, null);
// add english
- $li = $("<li>")
- .text("en")
- .data("locale", "en")
- .appendTo($ul);
+ addLocale("en", "en");
// inspect all children of dirEntry
entries.forEach(function (entry) {
@@ -250,13 +246,12 @@ define(function (require, exports, module) {
label += match[2].toUpperCase();
}
- var $li = $("<li>")
- .text(label)
- .data("locale", language)
- .appendTo($ul);
+ addLocale(label, language);
}
}
});
+
+ $select.val(curLocale);
});
});
}
View
279 src/extensions/default/HtmlEntityCodeHints/SpecialChars.json
@@ -0,0 +1,279 @@
+[
+ "&#33",
+ "&#35",
+ "&#36",
+ "&#37",
+ "&#39",
+ "&#40",
+ "&#41",
+ "&#42",
+ "&#43",
+ "&#44",
+ "&#45",
+ "&#46",
+ "&#58",
+ "&#59",
+ "&#61",
+ "&#63",
+ "&#64",
+ "&#91",
+ "&#92",
+ "&#93",
+ "&#94",
+ "&#95",
+ "&#96",
+ "&#123",
+ "&#124",
+ "&#125",
+ "&#126",
+ "&#8226",
+ "&#9679",
+
+ "&aacute",
+ "&Aacute",
+ "&acirc",
+ "&Acirc",
+ "&acute",
+ "&aelig",
+ "&AElig",
+ "&agrave",
+ "&Agrave",
+ "&alefsym",
+ "&alpha",
+ "&Alpha",
+ "&amp",
+ "&and",
+ "&ang",
+ "&aring",
+ "&Aring",
+ "&asymp",
+ "&atilde",
+ "&Atilde",
+ "&auml",
+ "&Auml",
+ "&bdquo",
+ "&beta",
+ "&Beta",
+ "&brvbar",
+ "&bull",
+ "&cap",
+ "&ccedil",
+ "&Ccedil",
+ "&cedil",
+ "&cent",
+ "&chi",
+ "&Chi",
+ "&circ",
+ "&clubs",
+ "&cong",
+ "&copy",
+ "&crarr",
+ "&cup",
+ "&curren",
+ "&dagger",
+ "&Dagger",
+ "&darr",
+ "&dArr",
+ "&deg",
+ "&delta",
+ "&Delta",
+ "&diams",
+ "&die",
+ "&divide",
+ "&eacute",
+ "&Eacute",
+ "&ecirc",
+ "&Ecirc",
+ "&egrave",
+ "&Egrave",
+ "&empty",
+ "&emsp",
+ "&ensp",
+ "&epsilon",
+ "&Epsilon",
+ "&equiv",
+ "&eta",
+ "&Eta",
+ "&eth",
+ "&ETH",
+ "&euml",
+ "&Euml",
+ "&euro",
+ "&exist",
+ "&forall",
+ "&frac12",
+ "&frac14",
+ "&frac34",
+ "&frasl",
+ "&gamma",
+ "&Gamma",
+ "&ge",
+ "&gt",
+ "&harr",
+ "&hArr",
+ "&hearts",
+ "&hellip",
+ "&iacute",
+ "&Iacute",
+ "&icirc",
+ "&Icirc",
+ "&iexcl",
+ "&igrave",
+ "&Igrave",
+ "&image",
+ "&infin",
+ "&int",
+ "&iota",
+ "&Iota",
+ "&iquest",
+ "&isin",
+ "&iuml",
+ "&Iuml",
+ "&kappa",
+ "&Kappa",
+ "&lambda",
+ "&Lambda",
+ "&lang",
+ "&laquo",
+ "&larr",
+ "&lArr",
+ "&lceil",
+ "&ldquo",
+ "&le",
+ "&lfloor",
+ "&lowast",
+ "&loz",
+ "&lrm",
+ "&lsaquo",
+ "&lsquo",
+ "&lt",
+ "&macr",
+ "&mdash",
+ "&micro",
+ "&middot",
+ "&minus",
+ "&mu",
+ "&Mu",
+ "&nabla",
+ "&nbsp",
+ "&ndash",
+ "&ne",
+ "&ni",
+ "&not",
+ "&notin",
+ "&nsub",
+ "&ntilde",
+ "&Ntilde",
+ "&nu",
+ "&Nu",
+ "&oacute",
+ "&Oacute",
+ "&ocirc",
+ "&Ocirc",
+ "&ograve",
+ "&Ograve",
+ "&oline",
+ "&omega",
+ "&Omega",
+ "&omicron",
+ "&Omicron",
+ "&oplus",
+ "&or",
+ "&ordf",
+ "&ordm",
+ "&oslash",
+ "&Oslash",
+ "&otilde",
+ "&Otilde",
+ "&otimes",
+ "&ouml",
+ "&Ouml",
+ "&para",
+ "&part",
+ "&permil",
+ "&perp",
+ "&phi",
+ "&Phi",
+ "&pi",
+ "&Pi",
+ "&piv",
+ "&plusmn",
+ "&pound",
+ "&prime",
+ "&Prime",
+ "&prod",
+ "&prop",
+ "&psi",
+ "&Psi",
+ "&quot",
+ "&radic",
+ "&rang",
+ "&raquo",
+ "&rarr",
+ "&rArr",
+ "&rceil",
+ "&rdquo",
+ "&real",
+ "&reg",
+ "&rfloor",
+ "&rho",
+ "&Rho",
+ "&rlm",
+ "&rsaquo",
+ "&rsquo",
+ "&sbquo",
+ "&Scaron",
+ "&scaron",
+ "&sdot",
+ "&sect",
+ "&shy",
+ "&sigma",
+ "&Sigma",
+ "&sim",
+ "&spades",
+ "&sub",
+ "&sube",
+ "&sum",
+ "&sup",
+ "&supe",
+ "&sup1",
+ "&sup2",
+ "&sup3",
+ "&szlig",
+ "&tau",
+ "&Tau",
+ "&there4",
+ "&theta",
+ "&Theta",
+ "&thetasym",
+ "&thinsp",
+ "&thorn",
+ "&THORN",
+ "&times",
+ "&tilde",
+ "&trade",
+ "&uacute",
+ "&Uacute",
+ "&uarr",
+ "&uArr",
+ "&ucirc",
+ "&Ucirc",
+ "&ugrave",
+ "&Ugrave",
+ "&uml",
+ "&upsih",
+ "&upsilon",
+ "&Upsilon",
+ "&uuml",
+ "&Uuml",
+ "&weierp",
+ "&xi",
+ "&Xi",
+ "&yacute",
+ "&Yacute",
+ "&yen",
+ "&yuml",
+ "&zeta",
+ "&Zeta",
+ "&zwnj"
+]
View
241 src/extensions/default/HtmlEntityCodeHints/main.js
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
+/*global define, brackets, $ */
+
+define(function (require, exports, module) {
+ "use strict";
+
+ // Load dependent modules
+ var AppInit = brackets.getModule("utils/AppInit"),
+ CodeHintManager = brackets.getModule("editor/CodeHintManager"),
+ ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
+ HTMLUtils = brackets.getModule("language/HTMLUtils"),
+ HtmlSpecialChars = require("text!SpecialChars.json"),
+ specialChars;
+
+ /**
+ * Encodes the special Char value given.
+ *
+ * @param {String} value
+ * The value to encode
+ *
+ * @return {String}
+ * The encoded string
+ */
+ function _encodeValue(value) {
+ return (value.indexOf("#") === -1) ? value.replace("&", "&amp;") : value.replace("&", "&amp;").replace("#", "&#35;");
+ }
+
+ /**
+ * Decodes the special Char value given.
+ *
+ * @param {String} value
+ * The value to decode
+ *
+ * @return {String}
+ * The decoded string
+ */
+ function _decodeValue(value) {
+ return value.replace("&#35;", "#").replace("&amp;", "&").replace("&#59;", ";");
+ }
+
+ /**
+ * @constructor
+ */
+ function SpecialCharHints() {
+ this.primaryTriggerKeys = "&ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#0123456789";
+ this.currentQuery = "";
+ }
+
+ /**
+ * Determines whether HtmlSpecialChar hints are available in the current editor
+ * context.
+ *
+ * @param {Editor} editor
+ * A non-null editor object for the active window.
+ *
+ * @param {String} implicitChar
+ * Either null, if the hinting request was explicit, or a single character
+ * that represents the last insertion and that indicates an implicit
+ * hinting request.
+ *
+ * @return {Boolean}
+ * Determines whether the current provider is able to provide hints for
+ * the given editor context and, in case implicitChar is non- null,
+ * whether it is appropriate to do so.
+ */
+ SpecialCharHints.prototype.hasHints = function (editor, implicitChar) {
+ this.editor = editor;
+
+ var query = this._getQuery();
+
+ if (implicitChar === null) {
+ return query !== null;
+ }
+
+ return implicitChar === "&" || query !== null;
+ };
+
+ /**
+ * Returns a list of avaliable HtmlSpecialChar hints if possible for the current
+ * editor context.
+ *
+ * @param {String} implicitChar
+ * Either null, if the hinting request was explicit, or a single character
+ * that represents the last insertion and that indicates an implicit
+ * hinting request.
+ *
+ * @return {Object<hints: Array<(String + jQuery.Obj)>, match: String, selectInitial: Boolean>}
+ * Null if the provider wishes to end the hinting session. Otherwise, a
+ * response object that provides 1. a sorted array hints that consists
+ * of strings; 2. a string match that is used by the manager to emphasize
+ * matching substrings when rendering the hint list; and 3. a boolean that
+ * indicates whether the first result, if one exists, should be selected
+ * by default in the hint list window.
+ */
+ SpecialCharHints.prototype.getHints = function (implicitChar) {
+ var query,
+ result;
+
+ if (this.primaryTriggerKeys.indexOf(implicitChar) !== -1 || implicitChar === null) {
+ this.currentQuery = query = this._getQuery();
+ result = $.map(specialChars, function (value, index) {
+ if (value.indexOf(query) === 0) {
+ var shownValue = _encodeValue(value);
+ return shownValue + "&#59; <span class='entity-display-character'>" + value + ";</span>";
+ }
+ }).sort(this._internalSort);
+
+ query = _encodeValue(query);
+ return {
+ hints: result,
+ match: query,
+ selectInitial: true
+ };
+ }
+
+ return null;
+ };
+
+ /**
+ * Sort function used internally when sorting the Hints
+ *
+ * @param {String} value
+ * The value to decode
+ *
+ * @return {String}
+ * The decoded string
+ */
+ SpecialCharHints.prototype._internalSort = function (a, b) {
+ a = _decodeValue(a.slice(0, a.indexOf(" "))).toLowerCase();
+ b = _decodeValue(b.slice(0, b.indexOf(" "))).toLowerCase();
+
+ if (a.indexOf("#") !== -1 && b.indexOf("#") !== -1) {
+ var num1 = parseInt(a.slice(a.indexOf("#") + 1, a.length - 1), 10),
+ num2 = parseInt(b.slice(b.indexOf("#") + 1, b.length - 1), 10);
+
+ return (num1 === num2) ? 0 : (num1 > num2) ? 1 : -1;
+ }
+
+ return a.localeCompare(b);
+ };
+
+ /**
+ * Returns a query for the Hints
+ *
+ * @return {String}
+ * The Query for which to search
+ */
+ SpecialCharHints.prototype._getQuery = function () {
+ var query,
+ lineContent,
+ startChar,
+ endChar;
+
+ query = "&";
+
+ lineContent = this.editor.document.getRange({
+ line: this.editor.getCursorPos().line,
+ ch: 0
+ }, this.editor.getCursorPos());
+
+ startChar = lineContent.lastIndexOf("&");
+ endChar = lineContent.lastIndexOf(";");
+
+ if (endChar < startChar) {
+ query = this.editor.document.getRange({
+ line: this.editor.getCursorPos().line,
+ ch: startChar
+ }, this.editor.getCursorPos());
+ }
+
+ if (startChar !== -1 && HTMLUtils.getTagInfo(this.editor, this.editor.getCursorPos()).tagName === "") {
+ return query;
+ }
+
+ return null;
+ };
+
+ /**
+ * Inserts a given HtmlSpecialChar hint into the current editor context.
+ *
+ * @param {String} completition
+ * The hint to be inserted into the editor context.
+ *
+ * @return {Boolean}
+ * Indicates whether the manager should follow hint insertion with an
+ * additional explicit hint request.
+ */
+ SpecialCharHints.prototype.insertHint = function (completion) {
+ var start = {line: -1, ch: -1},
+ end = {line: -1, ch: -1},
+ cursor = this.editor.getCursorPos();
+
+ end.line = start.line = cursor.line;
+ start.ch = cursor.ch - this.currentQuery.length;
+ end.ch = start.ch + this.currentQuery.length;
+ completion = completion.slice(0, completion.indexOf(" "));
+ completion = _decodeValue(completion);
+ if (start.ch !== end.ch) {
+ this.editor.document.replaceRange(completion, start, end);
+ } else {
+ this.editor.document.replaceRange(completion, start);
+ }
+
+ return false;
+ };
+
+ AppInit.appReady(function () {
+ ExtensionUtils.loadStyleSheet(module, "styles.css");
+ // Parse JSON files
+ specialChars = JSON.parse(HtmlSpecialChars);
+
+ // Register code hint providers
+ var specialCharHints = new SpecialCharHints();
+
+ CodeHintManager.registerHintProvider(specialCharHints, ["html"], 1);
+ });
+});
View
3 src/extensions/default/HtmlEntityCodeHints/styles.css
@@ -0,0 +1,3 @@
+span.entity-display-character {
+ float: right;
+}
View
3 src/nls/root/strings.js
@@ -127,9 +127,10 @@ define({
// Switch language
"LANGUAGE_TITLE" : "Switch Language",
- "LANGUAGE_MESSAGE" : "Please select the desired language from the list below:",
+ "LANGUAGE_MESSAGE" : "Language:",
"LANGUAGE_SUBMIT" : "Reload {APP_NAME}",
"LANGUAGE_CANCEL" : "Cancel",
+ "LANGUAGE_SYSTEM_DEFAULT" : "System Default",
/**
* ProjectManager
View
3 src/project/ProjectManager.js
@@ -388,11 +388,10 @@ define(function (require, exports, module) {
plugins : ["ui", "themes", "json_data", "crrm", "sort"],
ui : { select_limit: 1, select_multiple_modifier: "", select_range_modifier: "" },
json_data : { data: treeDataProvider, correct_state: false },
- core : { animation: 0 },
+ core : { animation: 0, strings : { loading : Strings.PROJECT_LOADING, new_node : "New node" } },
themes : { theme: "brackets", url: "styles/jsTreeTheme.css", dots: false, icons: false },
//(note: our actual jsTree theme CSS lives in brackets.less; we specify an empty .css
// file because jsTree insists on loading one itself)
- strings : { loading : Strings.PROJECT_LOADING, new_node : "New node" },
sort : function (a, b) {
if (brackets.platform === "win") {
// Windows: prepend folder names with a '0' and file names with a '1' so folders are listed first
View
4 src/styles/brackets_patterns_override.less
@@ -361,6 +361,10 @@
color: @grayDark;
}
+.dialog-message select {
+ margin-left: 10px;
+}
+
.dialog-filename {
font-weight: @font-weight-semibold;
}
View
4 src/utils/Global.js
@@ -77,6 +77,10 @@ define(function (require, exports, module) {
global.brackets.platform = "win";
}
+ global.brackets.isLocaleDefault = function () {
+ return !global.localStorage.getItem("locale");
+ };
+
global.brackets.getLocale = function () {
// By default use the locale that was determined in brackets.js
return global.localStorage.getItem("locale") || global.require.s.contexts._.config.locale;

0 comments on commit c6fc7f1

Please sign in to comment.
Something went wrong with that request. Please try again.