diff --git a/src/document/ChangedDocumentTracker.js b/src/document/ChangedDocumentTracker.js index b7e95bbc2..4b339ae0a 100644 --- a/src/document/ChangedDocumentTracker.js +++ b/src/document/ChangedDocumentTracker.js @@ -40,6 +40,7 @@ define(function (require, exports, module) { * changed when the Brackets window loses and regains focus. Does not * read timestamps of files on disk. Clients may optionally track file * timestamps on disk independently. + * @constructor */ function ChangedDocumentTracker() { var self = this; diff --git a/src/editor/Editor.js b/src/editor/Editor.js index 8274338b5..2682195b7 100644 --- a/src/editor/Editor.js +++ b/src/editor/Editor.js @@ -381,6 +381,12 @@ define(function (require, exports, module) { var nonWS = lineStr.search(/\S/); if (nonWS === -1 || nonWS >= cursor.ch) { + if (nonWS === -1) { + // if the line is all whitespace, move the cursor to the end of the line + // before indenting so that embedded whitespace such as indents are not + // orphaned to the right of the electric char being inserted + this.setCursorPos(cursor.line, this.document.getLine(cursor.line).length); + } // Need to do the auto-indent on a timeout to ensure // the keypress is handled before auto-indenting. // This is the same timeout value used by the diff --git a/src/extensibility/ExtensionManager.js b/src/extensibility/ExtensionManager.js index 430030861..15a45e393 100644 --- a/src/extensibility/ExtensionManager.js +++ b/src/extensibility/ExtensionManager.js @@ -373,11 +373,12 @@ define(function (require, exports, module) { * Updates an installed extension with the given package file. * @param {string} id of the extension * @param {string} packagePath path to the package file + * @param {boolean=} keepFile Flag to keep extension package file, default=false * @return {$.Promise} A promise that's resolved when the extension is updated or * rejected with an error if there's a problem with the update. */ - function update(id, packagePath) { - return Package.installUpdate(packagePath, id); + function update(id, packagePath, keepFile) { + return Package.installUpdate(packagePath, id, keepFile); } /** @@ -386,8 +387,11 @@ define(function (require, exports, module) { */ function cleanupUpdates() { Object.keys(_idsToUpdate).forEach(function (id) { - var filename = _idsToUpdate[id].localPath; - if (filename) { + var installResult = _idsToUpdate[id], + keepFile = installResult.keepFile, + filename = installResult.localPath; + + if (filename && !keepFile) { FileSystem.getFileForPath(filename).unlink(); } }); @@ -461,7 +465,7 @@ define(function (require, exports, module) { if (!installationResult) { return; } - if (installationResult.localPath) { + if (installationResult.localPath && !installationResult.keepFile) { FileSystem.getFileForPath(installationResult.localPath).unlink(); } delete _idsToUpdate[id]; @@ -513,7 +517,7 @@ define(function (require, exports, module) { Object.keys(_idsToUpdate), function (id) { var installationResult = _idsToUpdate[id]; - return update(installationResult.name, installationResult.localPath); + return update(installationResult.name, installationResult.localPath, installationResult.keepFile); } ); } @@ -571,6 +575,31 @@ define(function (require, exports, module) { }, []); } + /** + * Toggles between truncated and full length extension descriptions + * @param {string} id The id of the extension clicked + * @param {JQueryElement} $element The DOM element of the extension clicked + * @param {boolean} showFull true if full length description should be shown, false for shorten version. + */ + function toggleDescription(id, $element, showFull) { + var description, linkTitle, + entry = extensions[id]; + + // Toggle between appropriate descriptions and link title, + // depending on if extension is installed or not + if (showFull) { + description = entry.installInfo ? entry.installInfo.metadata.description : entry.registryInfo.metadata.description; + linkTitle = Strings.VIEW_TRUNCATED_DESCRIPTION; + } else { + description = entry.installInfo ? entry.installInfo.metadata.shortdescription : entry.registryInfo.metadata.shortdescription; + linkTitle = Strings.VIEW_COMPLETE_DESCRIPTION; + } + + $element.attr("data-toggle-desc", showFull ? "trunc-desc" : "expand-desc") + .attr("title", linkTitle) + .prev(".ext-full-description").html(description); + } + // Listen to extension load and loadFailed events $(ExtensionLoader) .on("load", _handleExtensionLoad) @@ -596,7 +625,7 @@ define(function (require, exports, module) { exports.updateExtensions = updateExtensions; exports.getAvailableUpdates = getAvailableUpdates; exports.cleanAvailableUpdates = cleanAvailableUpdates; - + exports.toggleDescription = toggleDescription; exports.ENABLED = ENABLED; exports.START_FAILED = START_FAILED; diff --git a/src/extensibility/ExtensionManagerDialog.js b/src/extensibility/ExtensionManagerDialog.js index f50c7203b..392863ef3 100644 --- a/src/extensibility/ExtensionManagerDialog.js +++ b/src/extensibility/ExtensionManagerDialog.js @@ -27,8 +27,11 @@ define(function (require, exports, module) { "use strict"; - var Dialogs = require("widgets/Dialogs"), + var _ = require("thirdparty/lodash"), + Dialogs = require("widgets/Dialogs"), DefaultDialogs = require("widgets/DefaultDialogs"), + FileSystem = require("filesystem/FileSystem"), + FileUtils = require("file/FileUtils"), Package = require("extensibility/Package"), Strings = require("strings"), StringUtils = require("utils/StringUtils"), @@ -48,6 +51,11 @@ define(function (require, exports, module) { var _activeTabIndex; + function _stopEvent(event) { + event.stopPropagation(); + event.preventDefault(); + } + /** * @private * Triggers changes requested by the dialog UI. @@ -156,6 +164,98 @@ define(function (require, exports, module) { }); } + + /** + * @private + * Install extensions from the local file system using the install dialog. + * @return {$.Promise} + */ + function _installUsingDragAndDrop() { + var installZips = [], + updateZips = [], + deferred = new $.Deferred(), + validatePromise; + + brackets.app.getDroppedFiles(function (err, paths) { + if (err) { + // Only possible error is invalid params, silently ignore + console.error(err); + deferred.resolve(); + return; + } + + // Parse zip files and separate new installs vs. updates + validatePromise = Async.doInParallel_aggregateErrors(paths, function (path) { + var result = new $.Deferred(); + + FileSystem.resolve(path, function (err, file) { + var extension = FileUtils.getFileExtension(path), + isZip = file.isFile && (extension === "zip"), + errStr; + + if (err) { + errStr = FileUtils.getFileErrorString(err); + } else if (!isZip) { + errStr = Strings.INVALID_ZIP_FILE; + } + + if (errStr) { + result.reject(errStr); + return; + } + + // Call validate() so that we open the local zip file and parse the + // package.json. We need the name to detect if this zip will be a + // new install or an update. + Package.validate(path, { requirePackageJSON: true }).done(function (info) { + if (info.errors.length) { + result.reject(Package.formatError(info.errors)); + return; + } + + var extensionName = info.metadata.name, + extensionInfo = ExtensionManager.extensions[extensionName], + isUpdate = extensionInfo && !!extensionInfo.installInfo; + + if (isUpdate) { + updateZips.push(file); + } else { + installZips.push(file); + } + + result.resolve(); + }).fail(function (err) { + result.reject(Package.formatError(err)); + }); + }); + + return result.promise(); + }); + + validatePromise.done(function () { + var installPromise = Async.doSequentially(installZips, function (file) { + return InstallExtensionDialog.installUsingDialog(file); + }); + + var updatePromise = installPromise.then(function () { + return Async.doSequentially(updateZips, function (file) { + return InstallExtensionDialog.updateUsingDialog(file).done(function (result) { + ExtensionManager.updateFromDownload(result); + }); + }); + }); + + // InstallExtensionDialog displays it's own errors, always + // resolve the outer promise + updatePromise.always(deferred.resolve); + }).fail(function (errorArray) { + deferred.reject(errorArray); + }); + }); + + return deferred.promise(); + } + /** * @private * Show a dialog that allows the user to browse and manage extensions. @@ -296,9 +396,7 @@ define(function (require, exports, module) { // Open dialog to Installed tab if extension updates are available if ($("#toolbar-extension-manager").hasClass('updatesAvailable')) { $dlg.find(".nav-tabs a.installed").tab("show"); - } - // Otherwise show the first tab - else { + } else { // Otherwise show the first tab $dlg.find(".nav-tabs a:first").tab("show"); } }); @@ -309,6 +407,86 @@ define(function (require, exports, module) { InstallExtensionDialog.showDialog().done(ExtensionManager.updateFromDownload); }); + // Handle the drag/drop zone + var $dropzone = $("#install-drop-zone"), + $dropmask = $("#install-drop-zone-mask"); + + $dropzone + .on("dragover", function (event) { + _stopEvent(event); + + if (!event.originalEvent.dataTransfer.files) { + return; + } + + var items = event.originalEvent.dataTransfer.items, + isValidDrop = false; + + isValidDrop = _.every(items, function (item) { + if (item.kind === "file") { + var entry = item.webkitGetAsEntry(), + extension = FileUtils.getFileExtension(entry.fullPath); + + return entry.isFile && extension === "zip"; + } + + return false; + }); + + if (isValidDrop) { + // Set an absolute width to stabilize the button size + $dropzone.width($dropzone.width()); + + // Show drop styling and message + $dropzone.removeClass("drag"); + $dropzone.addClass("drop"); + } else { + event.originalEvent.dataTransfer.dropEffect = "none"; + } + }) + .on("drop", _stopEvent); + + $dropmask + .on("dragover", function (event) { + _stopEvent(event); + event.originalEvent.dataTransfer.dropEffect = "copy"; + }) + .on("dragleave", function () { + $dropzone.removeClass("drop"); + $dropzone.addClass("drag"); + }) + .on("drop", function (event) { + _stopEvent(event); + + if (event.originalEvent.dataTransfer.files) { + // Attempt install + _installUsingDragAndDrop().fail(function (errorArray) { + var message = Strings.INSTALL_EXTENSION_DROP_ERROR; + + message += ""; + + Dialogs.showModalDialog( + DefaultDialogs.DIALOG_ID_ERROR, + Strings.EXTENSION_MANAGER_TITLE, + message + ); + }).always(function () { + $dropzone.removeClass("validating"); + $dropzone.addClass("drag"); + }); + + // While installing, show validating message + $dropzone.removeClass("drop"); + $dropzone.addClass("validating"); + } + }); + return new $.Deferred().resolve(dialog).promise(); } diff --git a/src/extensibility/ExtensionManagerView.js b/src/extensibility/ExtensionManagerView.js index 95b785db7..e92b17db1 100644 --- a/src/extensibility/ExtensionManagerView.js +++ b/src/extensibility/ExtensionManagerView.js @@ -35,7 +35,7 @@ define(function (require, exports, module) { InstallExtensionDialog = require("extensibility/InstallExtensionDialog"), LocalizationUtils = require("utils/LocalizationUtils"), itemTemplate = require("text!htmlContent/extension-manager-view-item.html"); - + /** * Creates a view enabling the user to install and manage extensions. Must be initialized * with initialize(). When the view is closed, dispose() must be called. @@ -110,7 +110,7 @@ define(function (require, exports, module) { * The individual views for each item, keyed by the extension ID. */ ExtensionManagerView.prototype._itemViews = null; - + /** * @private * Attaches our event handlers. We wait to do this until we've fully fetched the extension list. @@ -154,6 +154,10 @@ define(function (require, exports, module) { ExtensionManager.markForRemoval($target.attr("data-extension-id"), true); } else if ($target.hasClass("undo-update")) { ExtensionManager.removeUpdate($target.attr("data-extension-id")); + } else if ($target.attr("data-toggle-desc") === "expand-desc") { + ExtensionManager.toggleDescription($target.attr("data-extension-id"), $target, true); + } else if ($target.attr("data-toggle-desc") === "trunc-desc") { + ExtensionManager.toggleDescription($target.attr("data-extension-id"), $target, false); } }) .on("click", "button.install", function (e) { @@ -206,7 +210,11 @@ define(function (require, exports, module) { // (or registry is offline). These flags *should* always be ignored in that scenario, but just in case... context.isCompatible = context.isCompatibleLatest = true; } - + + if (info.metadata.description !== undefined) { + info.metadata.shortdescription = StringUtils.truncate(info.metadata.description, 200); + } + context.isMarkedForRemoval = ExtensionManager.isMarkedForRemoval(info.metadata.name); context.isMarkedForUpdate = ExtensionManager.isMarkedForUpdate(info.metadata.name); diff --git a/src/extensibility/InstallExtensionDialog.js b/src/extensibility/InstallExtensionDialog.js index 7b111ba61..c86cde632 100644 --- a/src/extensibility/InstallExtensionDialog.js +++ b/src/extensibility/InstallExtensionDialog.js @@ -29,6 +29,7 @@ define(function (require, exports, module) { "use strict"; var Dialogs = require("widgets/Dialogs"), + File = require("filesystem/File"), StringUtils = require("utils/StringUtils"), Strings = require("strings"), Commands = require("command/Commands"), @@ -285,7 +286,7 @@ define(function (require, exports, module) { } else if (this._state === STATE_ALREADY_INSTALLED) { // If we were prompting the user about overwriting a previous installation, // and the user cancels, we can delete the downloaded file. - if (this._installResult && this._installResult.localPath) { + if (this._installResult && this._installResult.localPath && !this._installResult.keepFile) { var filename = this._installResult.localPath; FileSystem.getFileForPath(filename).unlink(); } @@ -404,13 +405,34 @@ define(function (require, exports, module) { /** Mediates between this module and the Package extension-installation utils. Mockable for unit-testing. */ - function InstallerFacade() { } + function InstallerFacade(isLocalFile) { + this._isLocalFile = isLocalFile; + } + InstallerFacade.prototype.install = function (url) { if (this.pendingInstall) { console.error("Extension installation already pending"); return new $.Deferred().reject("DOWNLOAD_ID_IN_USE").promise(); } - this.pendingInstall = Package.installFromURL(url); + + if (this._isLocalFile) { + var deferred = new $.Deferred(); + + this.pendingInstall = { + promise: deferred.promise(), + cancel: function () { + // Can't cancel local zip installs + } + }; + + Package.installFromPath(url).then(function (installationResult) { + // Flag to keep zip files for local file installation + installationResult.keepFile = true; + deferred.resolve(installationResult); + }, deferred.reject); + } else { + this.pendingInstall = Package.installFromURL(url); + } // Store now since we'll null pendingInstall immediately if the promise was resolved synchronously var promise = this.pendingInstall.promise; @@ -440,14 +462,16 @@ define(function (require, exports, module) { /** * @private * Show the installation dialog and automatically begin installing the given URL. - * @param {string=} urlToInstall If specified, immediately starts installing the given file as if the user had + * @param {(string|File)=} urlOrFileToInstall If specified, immediately starts installing the given file as if the user had * specified it. * @return {$.Promise} A promise object that will be resolved when the selected extension * has finished installing, or rejected if the dialog is cancelled. */ - function installUsingDialog(urlToInstall, _isUpdate) { - var dlg = new InstallExtensionDialog(new InstallerFacade(), _isUpdate); - return dlg.show(urlToInstall); + function installUsingDialog(urlOrFileToInstall, _isUpdate) { + var isLocalFile = (urlOrFileToInstall instanceof File), + dlg = new InstallExtensionDialog(new InstallerFacade(isLocalFile), _isUpdate); + + return dlg.show(urlOrFileToInstall.fullPath || urlOrFileToInstall); } /** diff --git a/src/extensibility/Package.js b/src/extensibility/Package.js index dd26bfa47..e5d95cf2e 100644 --- a/src/extensibility/Package.js +++ b/src/extensibility/Package.js @@ -273,6 +273,51 @@ define(function (require, exports, module) { }); } + /** + * On success, resolves with an extension metadata object; at that point, the extension has already + * started running in Brackets. On failure (including validation errors), rejects with an error object. + * + * An error object consists of either a string error code OR an array where the first entry is the error + * code and the remaining entries are further info. The error code string is one of either + * ExtensionsDomain.Errors or Package.Errors. Use formatError() to convert an error object to a friendly, + * localized error message. + * + * @param {string} path Absolute path to the package zip file + * @param {?string} filenameHint Hint for the extension folder's name (used in favor of + * path's filename if present, and if no package metadata present). + * @return {$.Promise} A promise that is rejected if there are errors during + * install or the extension is disabled. + */ + function installFromPath(path, filenameHint) { + var d = new $.Deferred(); + + install(path, filenameHint) + .done(function (result) { + var installationStatus = result.installationStatus; + if (installationStatus === InstallationStatuses.ALREADY_INSTALLED || + installationStatus === InstallationStatuses.NEEDS_UPDATE || + installationStatus === InstallationStatuses.SAME_VERSION || + installationStatus === InstallationStatuses.OLDER_VERSION) { + d.resolve(result); + } else { + if (result.errors && result.errors.length > 0) { + // Validation errors - for now, only return the first one + d.reject(result.errors[0]); + } else if (result.disabledReason) { + // Extension valid but left disabled (wrong API version, extension name collision, etc.) + d.reject(result.disabledReason); + } else { + // Success! Extension is now running in Brackets + d.resolve(result); + } + } + }) + .fail(function (err) { + d.reject(err); + }); + + return d.promise(); + } /** * On success, resolves with an extension metadata object; at that point, the extension has already @@ -303,34 +348,19 @@ define(function (require, exports, module) { .done(function (downloadResult) { state = STATE_INSTALLING; - install(downloadResult.localPath, downloadResult.filenameHint) + installFromPath(downloadResult.localPath, downloadResult.filenameHint) .done(function (result) { var installationStatus = result.installationStatus; - if (installationStatus === InstallationStatuses.ALREADY_INSTALLED || - installationStatus === InstallationStatuses.NEEDS_UPDATE || - installationStatus === InstallationStatuses.SAME_VERSION || - installationStatus === InstallationStatuses.OLDER_VERSION) { - // We don't delete the file in this case, because it will be needed - // if the user is going to install the update. - state = STATE_SUCCEEDED; - result.localPath = downloadResult.localPath; - d.resolve(result); - } else { + + state = STATE_SUCCEEDED; + result.localPath = downloadResult.localPath; + + if (installationStatus === InstallationStatuses.INSTALLED) { + // Delete temp file FileSystem.getFileForPath(downloadResult.localPath).unlink(); - if (result.errors && result.errors.length > 0) { - // Validation errors - for now, only return the first one - state = STATE_FAILED; - d.reject(result.errors[0]); - } else if (result.disabledReason) { - // Extension valid but left disabled (wrong API version, extension name collision, etc.) - state = STATE_FAILED; - d.reject(result.disabledReason); - } else { - // Success! Extension is now running in Brackets - state = STATE_SUCCEEDED; - d.resolve(result); - } } + + d.resolve(result); }) .fail(function (err) { // File IO errors, internal error in install()/validate(), or extension startup crashed @@ -359,7 +389,9 @@ define(function (require, exports, module) { } /** - * Converts an error object as returned by install() or installFromURL() into a flattened, localized string. + * Converts an error object as returned by install(), installFromPath() or + * installFromURL() into a flattened, localized string. + * * @param {string|Array.} error * @return {string} */ @@ -406,10 +438,11 @@ define(function (require, exports, module) { * @param {string} path to package file * @param {?string} nameHint Hint for the extension folder's name (used in favor of * path's filename if present, and if no package metadata present). + * @param {boolean=} keepFile Flag to keep extension update, default=false * @return {$.Promise} A promise that is resolved when the extension is successfully * installed or rejected if there is a problem. */ - function installUpdate(path, nameHint) { + function installUpdate(path, nameHint, keepFile) { var d = new $.Deferred(); install(path, nameHint, true) .done(function (result) { @@ -423,7 +456,9 @@ define(function (require, exports, module) { d.reject(error); }) .always(function () { - FileSystem.getFileForPath(path).unlink(); + if (!keepFile) { + FileSystem.getFileForPath(path).unlink(); + } }); return d.promise(); } @@ -465,6 +500,7 @@ define(function (require, exports, module) { exports._getNodeConnectionDeferred = _getNodeConnectionDeferred; exports.installFromURL = installFromURL; + exports.installFromPath = installFromPath; exports.validate = validate; exports.install = install; exports.remove = remove; diff --git a/src/extensions/default/ThorDarkTheme/main.less b/src/extensions/default/ThorDarkTheme/main.less index fe1d5b493..071d22ec4 100644 --- a/src/extensions/default/ThorDarkTheme/main.less +++ b/src/extensions/default/ThorDarkTheme/main.less @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved. +// Copyright (c) 2014 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"), @@ -23,16 +23,16 @@ // Brackets-specific default font and color definitions -@import url("brackets_colors.less"); +//@import url("brackets_colors.less"); // Default theme -- all UI styling comes from variables in a theme // Themes can rely on variables defined above -@import url("brackets_theme_default.less"); +//@import url("brackets_theme_default.less"); // Include Codemirror styling overrides so that we can overrides proper values // for the theme. If you need to customize the tree, you also include jsTree.less // and even brackets_scrollbars.less -@import url("brackets_codemirror_override.less"); +//@import url("brackets_codemirror_override.less"); /* @@ -48,147 +48,115 @@ * in this file. */ -/* Overall Colors */ +/* Define some variables used in multiple places */ @background: #1d1f21; -@current-line: #000; @foreground: #c5c8c6; -@comment: #767676; -@orange: #d89333; -@blue: #6c9ef8; -@purple: #b77fdb; -@green: #85a300; -@red: #dc322f; -@aqua: #8abeb7; -@violet: #6c71c4; -@yellow: #f0c674; -@pink: #d85896; - -/* - * Background colors are ordered from least "intense" to most "intense" - * So, if the background is light, then @background-color-3 should be - * lightest, -2 should be darker, and -1 should be darker still. - * - * The opposite is true for a dark background -- background-color-3 should be - * the darkest, -2 should be lighter, and -1 should be lighter still. - */ -@background-color-1: lighten(@background, @bc-color-step-size*2); -@background-color-2: lighten(@background, @bc-color-step-size); -@background-color-3: @background; - -/* - * @content-color-stronger should be should be further away from the - * background color than @content-color (i.e. more contrasty). - * - * @content-color-weaker should be closer to the background color - * than @content-color (i.e. less contrasty). - */ -@content-color: @foreground; -@content-color-stronger: lighten(@foreground, @bc-color-step-size); -@content-color-weaker: darken(@foreground, @bc-color-step-size); +@bc-color-step-size: 10%; /* Code Styling */ -/* code accent colors */ -@accent-keyword: @blue; -@accent-atom: @orange; -@accent-number: @green; -@accent-def: @purple; -@accent-variable: @foreground; -@accent-variable-2: @foreground; -@accent-variable-3: @foreground; -@accent-property: @purple; -@accent-operator: @foreground; -@accent-comment: @comment; -@accent-string: @orange; -@accent-string-2: @orange; -@accent-meta: @foreground; -@accent-error: @red; -@accent-qualifier: @blue; -@accent-builtin: @blue; -@accent-bracket: @foreground; -@accent-tag: @blue; -@accent-attribute: @green; -@accent-header: @pink; -@accent-quote: @blue; -@accent-hr: @orange; -@accent-link: @purple; -@accent-rangeinfo: @violet; -@accent-minus: @red; -@accent-plus: @green; +/* Custom scrollbar colors */ +.platform-win & { + .CodeMirror-gutter-filler { + background-color: rgb(15, 15, 15); + } + // Note: when changing padding/margins, may need to adjust metrics in ScrollTrackMarkers.js -/* inline editor colors */ -@inline-background-color-1: lighten(@background, @bc-color-step-size); -@inline-background-color-2: lighten(@background, @bc-color-step-size*2); -@inline-background-color-3: rgba(0,0,0,0); + ::-webkit-scrollbar { + background-color: rgb(15, 15, 15); + } -@inline-color-1: darken(@foreground, @bc-color-step-size*2); -@inline-color-2: darken(@foreground, @bc-color-step-size); -@inline-color-3: @background; + ::-webkit-scrollbar-thumb { + box-shadow: 0 0 0 12px rgb(49, 49, 49) inset; + } + ::-webkit-scrollbar-thumb:hover, + ::-webkit-scrollbar-thumb:focus { + box-shadow: 0 0 0 12px rgb(89, 89, 89) inset; + } + ::-webkit-scrollbar-thumb:active { + box-shadow: 0 0 0 12px rgb(169, 169, 169) inset; + } +} -/* Selection colors */ -@selection-color-focused: #0050a0; -@selection-color-unfocused: #333f48; +.platform-linux & { + ::-webkit-scrollbar-thumb { + box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.24) inset; + } -@activeline-bgcolor: #2f2f2f; -@activeline-number: #fff; -@activeline-number-bgcolor: #000; -@matching-bracket: #2e5c00; + ::-webkit-scrollbar-thumb:window-inactive { + box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.12) inset; + } +} -/* Status Bar Colors */ -@status-bar-background-color: #1C1C1E; -@status-bar-border: rgba(255, 255, 255, 0.08); -@status-bar-text-color: #a1a1a1; -@status-bar-quiet-text-color: #666; -/* custom scrollbar colors */ -@win-scrollbar-track: rgb(15, 15, 15); -@win-scrollbar-thumb: rgb(49, 49, 49); -@win-scrollbar-thumb-hover: rgb(89, 89, 89); -@win-scrollbar-thumb-active: rgb(169, 169, 169); +.CodeMirror, .CodeMirror-scroll { + background-color: @background; + color: @foreground; +} -@linux-scrollbar-thumb: rgba(255, 255, 255, 0.24); -@linux-scrollbar-thumb-inactive: rgba(255, 255, 255, 0.12); +.CodeMirror-focused .CodeMirror-activeline-background { + background: #2f2f2f; +} +.show-line-padding .CodeMirror-focused .CodeMirror-activeline-background { + box-shadow: inset 15px 0 0 0 #000; +} +.CodeMirror-focused .CodeMirror-activeline { + .CodeMirror-gutter-elt { + background: #000; + color: #fff; + } + .inline-widget .CodeMirror-gutter-elt { + color: #767676; + } +} + +.cm-keyword, .cm-qualifier, .cm-builtin, .cm-tag, .cm-quote {color: #6c9ef8;} +.cm-atom, .cm-string, .cm-string-2, .cm-hr {color: #d89333;} +.cm-number, .cm-attribute, .cm-plus {color: #85a300;} +.cm-def, .cm-property {color: #b77fdb;} +.cm-variable, .cm-variable-2, .cm-variable-3, .cm-operator, .cm-meta, .cm-bracket {color: @foreground;} +.cm-comment {color: #767676;} +.cm-error, .cm-minus {color: #dc322f;} +.cm-header {color: #d85896;} +.cm-link {color: #b77fdb; text-decoration: none;} +.cm-rangeinfo {color: #6c71c4;} /* Extra CSS */ -.code-cursor() { - // to make a block cursor, use something like this: - // background-color: fadeout(@blue, 50%); - // border: none !important; - - // to make an I-cursor, use something like this: - border-left: 1px solid @content-color !important; +.CodeMirror-cursor { + border-left: 1px solid #c5c8c6 !important; } -.CodeMirror .CodeMirror-gutters { - // gutter border: - // border-right: 1px solid rgba(255, 255, 255, 0.03); +.CodeMirror-gutters { + background-color: @background; + border-right: none; } -.CodeMirror-focused .CodeMirror-activeline .CodeMirror-gutter-elt { - color: @comment; +.CodeMirror-focused .CodeMirror-activeline .CodeMirror-gutter-elt, .CodeMirror-linenumber { + color: #767676; } -#status-bar { - background: @status-bar-background-color; - border-top: 1px solid @status-bar-border; - color:@status-bar-text-color; +.CodeMirror .CodeMirror-selected { + background: #333f48; +} +.CodeMirror-focused .CodeMirror-selected { + background: #0050a0; } -#status-info { - color: @status-bar-text-color; +.CodeMirror-matchingbracket, .CodeMirror-matchingtag { + /* Ensure visibility against gray inline editor background */ + background-color: #2e5c00; + color: @foreground !important; } -#status-file { - color: @status-bar-quiet-text-color; +/* Inline editor styling */ + +.related-container .selection:before { + border-top: 9px solid black; + border-bottom: 9px solid black; } -#status-indicators { - background: @status-bar-background-color; - color: @status-bar-text-color; - - > div { - border-left: 1px solid @status-bar-border; - } -} +.inline-widget .CodeMirror, .inline-widget .CodeMirror-gutters { + background: transparent; +} \ No newline at end of file diff --git a/src/extensions/default/ThorLightTheme/main.less b/src/extensions/default/ThorLightTheme/main.less index b05bbeb21..a1691b226 100644 --- a/src/extensions/default/ThorLightTheme/main.less +++ b/src/extensions/default/ThorLightTheme/main.less @@ -18,27 +18,4 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -// Brackets-specific default font and color definitions -@import url("brackets_colors.less"); - -// Default theme -- all UI styling comes from variables in a theme -// Themes can rely on variables defined above -@import url("brackets_theme_default.less"); - -// Include Codemirror styling overrides so that we can overrides proper values -// for the theme. If you need to customize the tree, you also include jsTree.less -// and even brackets_scrollbars.less -@import url("brackets_codemirror_override.less"); - -/* - * Brackets Default Theme - * - * Defines all the variables that one can configure in a theme. This should - * contain all variables / mixins for UI styling that we want to be able to - * change in a theme. - * - * Throughout the rest of the LESS files we should _only_ use color - * variable names that are on the LHS of the list below. So, if we - * need a new color for some UI element, we should add a variable - * in this file. - */ +// This is the default theme and doesn't need to do anything! diff --git a/src/htmlContent/extension-manager-dialog.html b/src/htmlContent/extension-manager-dialog.html index 7e828bc32..805328d1c 100644 --- a/src/htmlContent/extension-manager-dialog.html +++ b/src/htmlContent/extension-manager-dialog.html @@ -16,7 +16,12 @@
diff --git a/src/htmlContent/extension-manager-view-item.html b/src/htmlContent/extension-manager-view-item.html index bd0fe9b8f..c966f681c 100644 --- a/src/htmlContent/extension-manager-view-item.html +++ b/src/htmlContent/extension-manager-view-item.html @@ -26,21 +26,25 @@ {{/isCompatibleLatest}} {{/isCompatible}} {{/showInstallButton}} - {{metadata.description}} - {{^metadata.description}} -

{{Strings.EXTENSION_NO_DESCRIPTION}}

- {{/metadata.description}} + + {{#metadata.shortdescription}} + {{metadata.shortdescription}} + {{/metadata.shortdescription}} + {{^metadata.shortdescription}} + {{#metadata.description}} + {{metadata.description}} + {{/metadata.description}} + {{^metadata.description}} +

{{Strings.EXTENSION_NO_DESCRIPTION}}

+ {{/metadata.description}} + {{/metadata.shortdescription}} +
+ {{#metadata.shortdescription}} + ... + {{/metadata.shortdescription}} {{#metadata.homepage}}

{{Strings.EXTENSION_MORE_INFO}}

{{/metadata.homepage}} - {{#metadata.keywords.length}} -
- {{Strings.EXTENSION_KEYWORDS}}: - {{#metadata.keywords}} - {{.}} - {{/metadata.keywords}} - - {{/metadata.keywords.length}} {{#translated}}
{{extensionTranslated}} diff --git a/src/nls/hr/strings.js b/src/nls/hr/strings.js index b2820b43b..85f495b86 100644 --- a/src/nls/hr/strings.js +++ b/src/nls/hr/strings.js @@ -282,18 +282,6 @@ define({ "CMD_SPLIT_SEL_INTO_LINES" : "Razdvoji odabrano u redove", "CMD_ADD_CUR_TO_NEXT_LINE" : "Dodaj kursor u sljedeći red", "CMD_ADD_CUR_TO_PREV_LINE" : "Dodaj kursor u prošli red", - "FIND_MENU" : "Nađi", - "CMD_FIND" : "Nađi", - "CMD_FIND_FIELD_PLACEHOLDER" : "Nađi\u2026", - "CMD_FIND_IN_FILES" : "Nađi u datotekama", - "CMD_FIND_IN_SELECTED" : "Nađi u odabranoj Datoteci/Mapi", - "CMD_FIND_IN_SUBTREE" : "Nađi u\u2026", - "CMD_FIND_NEXT" : "Nađi sljedeće", - "CMD_FIND_PREVIOUS" : "Nađi prethodno", - "CMD_FIND_ALL_AND_SELECT" : "Nađi sve i odaberi", - "CMD_ADD_NEXT_MATCH" : "Dodaj sljedeće slaganje u odabir", - "CMD_SKIP_CURRENT_MATCH" : "Preskoči i dodaj sljedeće slaganje", - "CMD_REPLACE" : "Zamijeni", "CMD_INDENT" : "Pomakni udesno", "CMD_UNINDENT" : "Pomakni ulijevo", "CMD_DUPLICATE" : "Udvostruči", @@ -307,6 +295,23 @@ define({ "CMD_TOGGLE_CLOSE_BRACKETS" : "Automatski zatvori zagrade", "CMD_SHOW_CODE_HINTS" : "Prikaži naznake (hintove) kôda", + // Search menu commands + "FIND_MENU" : "Nađi", + "CMD_FIND" : "Nađi", + "CMD_FIND_FIELD_PLACEHOLDER" : "Nađi\u2026", + "CMD_FIND_IN_FILES" : "Nađi u datotekama", + "CMD_FIND_IN_SELECTED" : "Nađi u odabranoj Datoteci/Mapi", + "CMD_FIND_IN_SUBTREE" : "Nađi u\u2026", + "CMD_FIND_NEXT" : "Nađi sljedeće", + "CMD_FIND_PREVIOUS" : "Nađi prethodno", + "CMD_FIND_ALL_AND_SELECT" : "Nađi sve i odaberi", + "CMD_ADD_NEXT_MATCH" : "Dodaj sljedeće slaganje u odabir", + "CMD_SKIP_CURRENT_MATCH" : "Preskoči i dodaj sljedeće slaganje", + "CMD_REPLACE" : "Zamijeni", + "CMD_REPLACE_IN_FILES" : "Zamijeni u datotekama", + "CMD_REPLACE_IN_SELECTED" : "Zamijeni u odabranoj datoteci/mapi", + "CMD_REPLACE_IN_SUBTREE" : "Zamijeni u\u2026", + // View menu commands "VIEW_MENU" : "Prikaz", "CMD_HIDE_SIDEBAR" : "Sakrij bočnu traku", diff --git a/src/nls/nl/strings.js b/src/nls/nl/strings.js index 9bc174bc6..5c771de10 100644 --- a/src/nls/nl/strings.js +++ b/src/nls/nl/strings.js @@ -124,14 +124,14 @@ define({ "BUTTON_NEXT" : "\u25B6", "BUTTON_PREV" : "\u25C0", - "BUTTON_NEXT_HINT" : "Volgende Overeenkomst", - "BUTTON_PREV_HINT" : "Vorige Overeenkomst", + "BUTTON_NEXT_HINT" : "Volgende overeenkomst", + "BUTTON_PREV_HINT" : "Vorige overeenkomst", - "OPEN_FILE" : "Open Bestand", - "SAVE_FILE_AS" : "Bewaar Bestand", + "OPEN_FILE" : "Bestand openen", + "SAVE_FILE_AS" : "Bestand opslaan", "CHOOSE_FOLDER" : "Kies een map", - "RELEASE_NOTES" : "Release Notes", + "RELEASE_NOTES" : "Release notes", "NO_UPDATE_TITLE" : "Je bent up to date!", "NO_UPDATE_MESSAGE" : "Je werkt met de laatste versie van {APP_NAME}.", @@ -202,97 +202,97 @@ define({ // File menu commands "FILE_MENU" : "Bestand", "CMD_FILE_NEW_UNTITLED" : "Nieuw", - "CMD_FILE_NEW" : "Nieuw Bestand", - "CMD_FILE_NEW_FOLDER" : "Nieuwe Map", - "CMD_FILE_OPEN" : "Open\u2026", - "CMD_ADD_TO_WORKING_SET" : "Voeg Toe Aan Werkset", + "CMD_FILE_NEW" : "Nieuw bestand", + "CMD_FILE_NEW_FOLDER" : "Map openen", + "CMD_FILE_OPEN" : "Bestand openen\u2026", + "CMD_ADD_TO_WORKING_SET" : "Voeg toe aan werkset", "CMD_OPEN_FOLDER" : "Open Map\u2026", "CMD_FILE_CLOSE" : "Sluit", - "CMD_FILE_CLOSE_ALL" : "Sluit alles", - "CMD_FILE_SAVE" : "Bewaar", - "CMD_FILE_SAVE_ALL" : "Bewaar Alles", - "CMD_FILE_SAVE_AS" : "Bewaar Als\u2026", - "CMD_LIVE_FILE_PREVIEW" : "Live Voorbeeld", - "CMD_PROJECT_SETTINGS" : "Project Instellingen\u2026", - "CMD_FILE_RENAME" : "Hernoem", + "CMD_FILE_CLOSE_ALL" : "Alles sluiten", + "CMD_FILE_SAVE" : "Opslaan", + "CMD_FILE_SAVE_ALL" : "Alles opslaan", + "CMD_FILE_SAVE_AS" : "Opslaan als\u2026", + "CMD_LIVE_FILE_PREVIEW" : "Live voorbeeld", + "CMD_PROJECT_SETTINGS" : "Project instellingen\u2026", + "CMD_FILE_RENAME" : "Bestand hernoemen", "CMD_FILE_DELETE" : "Verwijder", - "CMD_INSTALL_EXTENSION" : "Installeer Uitbreiding\u2026", + "CMD_INSTALL_EXTENSION" : "Installeer uitbreiding\u2026", "CMD_EXTENSION_MANAGER" : "Uitbreidingbeheer\u2026", - "CMD_FILE_REFRESH" : "Ververs Bestandsboom", - "CMD_QUIT" : "Stop", + "CMD_FILE_REFRESH" : "Ververs bestandsboom", + "CMD_QUIT" : "Stoppen", // Used in native File menu on Windows - "CMD_EXIT" : "Exit", + "CMD_EXIT" : "Afsluiten", // Edit menu commands - "EDIT_MENU" : "Wijzig", + "EDIT_MENU" : "Bewerken", "CMD_UNDO" : "Herstel", "CMD_REDO" : "Opnieuw", - "CMD_CUT" : "Knip", - "CMD_COPY" : "Kopieer", - "CMD_PASTE" : "Plak", - "CMD_SELECT_ALL" : "Selecteer Alles", - "CMD_SELECT_LINE" : "Selecteer Regel", + "CMD_CUT" : "Knippen", + "CMD_COPY" : "kopierën", + "CMD_PASTE" : "Plakken", + "CMD_SELECT_ALL" : "Alles selecteren", + "CMD_SELECT_LINE" : "Regel selecteren", "CMD_FIND" : "Zoek", - "CMD_FIND_IN_FILES" : "Zoek in Mappen", + "CMD_FIND_IN_FILES" : "Zoek in mappen", "CMD_FIND_IN_SUBTREE" : "Zoek in\u2026", - "CMD_FIND_NEXT" : "Zoek Volgende", - "CMD_FIND_PREVIOUS" : "Zoek Vorige", + "CMD_FIND_NEXT" : "Zoek volgende", + "CMD_FIND_PREVIOUS" : "Zoek vorige", "CMD_REPLACE" : "Vervang", "CMD_INDENT" : "Inspringen", - "CMD_UNINDENT" : "Insprong Verwijderen", + "CMD_UNINDENT" : "Inspringen verwijderen", "CMD_DUPLICATE" : "Dupliceer", "CMD_DELETE_LINES" : "Verwijder Regel", - "CMD_COMMENT" : "Zet Regel Commentaar Aan/Uit", - "CMD_BLOCK_COMMENT" : "Zet Blok Commentaar Aan/Uit", - "CMD_LINE_UP" : "Verplaats Regel naar Boven", - "CMD_LINE_DOWN" : "Verplaats Regel naar Beneden", - "CMD_OPEN_LINE_ABOVE" : "Open Regel Boven", - "CMD_OPEN_LINE_BELOW" : "Open Regel Beneden", - "CMD_TOGGLE_CLOSE_BRACKETS" : "Automatisch Accolades Sluiten", - "CMD_SHOW_CODE_HINTS" : "Toon Code Hints", + "CMD_COMMENT" : "Zet regel commentaar aan/uit", + "CMD_BLOCK_COMMENT" : "Zet blok commentaar aan/uit", + "CMD_LINE_UP" : "Verplaats regel naar boven", + "CMD_LINE_DOWN" : "Verplaats regel naar beneden", + "CMD_OPEN_LINE_ABOVE" : "Open regel boven", + "CMD_OPEN_LINE_BELOW" : "Open regel beneden", + "CMD_TOGGLE_CLOSE_BRACKETS" : "Automatisch accolades sluiten", + "CMD_SHOW_CODE_HINTS" : "Toon code hints", // View menu commands - "VIEW_MENU" : "Weergave", - "CMD_HIDE_SIDEBAR" : "Verberg Zijbalk", - "CMD_SHOW_SIDEBAR" : "Toon Zijbalk", - "CMD_INCREASE_FONT_SIZE" : "Vergroot Lettertype", - "CMD_DECREASE_FONT_SIZE" : "Verklein Lettertype", - "CMD_RESTORE_FONT_SIZE" : "Herstel Lettertype", - "CMD_SCROLL_LINE_UP" : "Scroll Regel naar Boven", - "CMD_SCROLL_LINE_DOWN" : "Scroll Regel naar Beneden", + "VIEW_MENU" : "Beeld", + "CMD_HIDE_SIDEBAR" : "Verberg zijbalk", + "CMD_SHOW_SIDEBAR" : "Toon zijbalk", + "CMD_INCREASE_FONT_SIZE" : "Vergroot lettertype", + "CMD_DECREASE_FONT_SIZE" : "Verklein lettertype", + "CMD_RESTORE_FONT_SIZE" : "Herstel lettertype", + "CMD_SCROLL_LINE_UP" : "Scroll regel naar Boven", + "CMD_SCROLL_LINE_DOWN" : "Scroll regel naar Beneden", "CMD_TOGGLE_LINE_NUMBERS" : "Regelnummers", - "CMD_TOGGLE_ACTIVE_LINE" : "Markeer Actieve Regel", - "CMD_TOGGLE_WORD_WRAP" : "Word Wrap", - "CMD_LIVE_HIGHLIGHT" : "Live Voorbeeld Markeren", - "CMD_VIEW_TOGGLE_INSPECTION" : "Lint Bestanden bij Opslaan", - "CMD_SORT_WORKINGSET_BY_ADDED" : "Sorteer op Toegevoegd", - "CMD_SORT_WORKINGSET_BY_NAME" : "Sorteer op Naam", - "CMD_SORT_WORKINGSET_BY_TYPE" : "Sorteer op Type", - "CMD_SORT_WORKINGSET_AUTO" : "Automatisch Sorteren", + "CMD_TOGGLE_ACTIVE_LINE" : "Markeer actieve regel", + "CMD_TOGGLE_WORD_WRAP" : "Word wrap", + "CMD_LIVE_HIGHLIGHT" : "Live voorbeeld markeren", + "CMD_VIEW_TOGGLE_INSPECTION" : "Lint bestanden bij opslaan", + "CMD_SORT_WORKINGSET_BY_ADDED" : "Sorteren op toegevoegd", + "CMD_SORT_WORKINGSET_BY_NAME" : "Sorteren op naam", + "CMD_SORT_WORKINGSET_BY_TYPE" : "Sorteren op type", + "CMD_SORT_WORKINGSET_AUTO" : "Automatisch sorteren", // Navigate menu Commands "NAVIGATE_MENU" : "Navigeer", - "CMD_QUICK_OPEN" : "Open Snel", - "CMD_GOTO_LINE" : "Ga naar Regel", - "CMD_GOTO_DEFINITION" : "Definitie Snel Zoeken", - "CMD_GOTO_FIRST_PROBLEM" : "Ga naar de eerstvolgende Fout/Waarschuwing", - "CMD_TOGGLE_QUICK_EDIT" : "Wijzig snel", - "CMD_TOGGLE_QUICK_DOCS" : "Snel naar Documentatie", - "CMD_QUICK_EDIT_PREV_MATCH" : "Vorige Overeenkomst", - "CMD_QUICK_EDIT_NEXT_MATCH" : "Volgende Overeenkomst", - "CMD_NEXT_DOC" : "Volgend Document", - "CMD_PREV_DOC" : "Vorig Document", - "CMD_SHOW_IN_TREE" : "Toon in Bestandsboom", - "CMD_SHOW_IN_OS" : "Toon in Besturingssysteem", + "CMD_QUICK_OPEN" : "Snel openen", + "CMD_GOTO_LINE" : "Ga naar regel", + "CMD_GOTO_DEFINITION" : "Definitie snel zoeken", + "CMD_GOTO_FIRST_PROBLEM" : "Ga naar de eerstvolgende fout/waarschuwing", + "CMD_TOGGLE_QUICK_EDIT" : "Snel wijzigen", + "CMD_TOGGLE_QUICK_DOCS" : "Snel naar documentatie", + "CMD_QUICK_EDIT_PREV_MATCH" : "Vorige overeenkomst", + "CMD_QUICK_EDIT_NEXT_MATCH" : "Volgende overeenkomst", + "CMD_NEXT_DOC" : "Volgend document", + "CMD_PREV_DOC" : "Vorig document", + "CMD_SHOW_IN_TREE" : "Toon in bestandsboom", + "CMD_SHOW_IN_OS" : "Toon in besturingssysteem", // Help menu commands "HELP_MENU" : "Help", - "CMD_CHECK_FOR_UPDATE" : "Controleer op Updates", + "CMD_CHECK_FOR_UPDATE" : "Controleer op updates", "CMD_HOW_TO_USE_BRACKETS" : "Hoe gebruik je {APP_NAME}", - "CMD_FORUM" : "{APP_NAME} Forum", + "CMD_FORUM" : "{APP_NAME} forum", "CMD_RELEASE_NOTES" : "Release Notes", "CMD_REPORT_AN_ISSUE" : "Rapporteer een probleem", - "CMD_SHOW_EXTENSIONS_FOLDER" : "Toon de Map met Uitbreidingen", + "CMD_SHOW_EXTENSIONS_FOLDER" : "Toon de map met Uitbreidingen", "CMD_TWITTER" : "{TWITTER_NAME} op Twitter", "CMD_ABOUT" : "Over {APP_TITLE}", @@ -302,53 +302,53 @@ define({ "OK" : "OK", "DONT_SAVE" : "Niet opslaan", "SAVE" : "Opslaan", - "CANCEL" : "Annuleer", - "DELETE" : "Verwijder", - "RELOAD_FROM_DISK" : "Laad opnieuw van Schijf", - "KEEP_CHANGES_IN_EDITOR" : "Behoud veranderingen in Editor", - "CLOSE_DONT_SAVE" : "Sluit (Bewaar Niet)", + "CANCEL" : "Annuleren", + "DELETE" : "Verwijderen", + "RELOAD_FROM_DISK" : "Opnieuw laden van schijf", + "KEEP_CHANGES_IN_EDITOR" : "Behoud veranderingen in editor", + "CLOSE_DONT_SAVE" : "Sluit (niet bewaren)", "RELAUNCH_CHROME" : "Herstart Chrome", "ABOUT" : "Over", - "CLOSE" : "Sluit", + "CLOSE" : "Sluiten", "ABOUT_TEXT_LINE1" : "sprint {VERSION_MINOR} {BUILD_TYPE} {VERSION}", "ABOUT_TEXT_LINE3" : "Kennisgevingen, voorwaarden en bepalingen met betrekking tot software van derden bevinden zich op {ADOBE_THIRD_PARTY} en op de pagina's, hierin door verwijzing opgenomen.", "ABOUT_TEXT_LINE4" : "Documentatie en broncode op https://github.com/adobe/brackets/", "ABOUT_TEXT_LINE5" : "Gemaakt met \u2764 en JavaScript door:", "ABOUT_TEXT_LINE6" : "Veel mensen (maar we hebben problemen met het laden van die data op dit moment).", - "ABOUT_TEXT_WEB_PLATFORM_DOCS" : "Web Platform Docs en het Web Platform grafisch logo zijn gelicentieerd onder een Creative Commons Attribution licentie, CC-BY 3.0 Unported.", - "UPDATE_NOTIFICATION_TOOLTIP" : "Er is een nieuwe build van {APP_NAME} beschikbaar! Klik hier voor details.", - "UPDATE_AVAILABLE_TITLE" : "Update Beschikbaar", - "UPDATE_MESSAGE" : "Hey, er is een nieuwe build van {APP_NAME} beschikbaar. Hier zijn een aantal van de nieuwe functies:", + "ABOUT_TEXT_WEB_PLATFORM_DOCS" : "Web Platform Docs en het Web Platform logo zijn gelicentieerd onder een Creative Commons Attribution licentie, CC-BY 3.0 Unported.", + "UPDATE_NOTIFICATION_TOOLTIP" : "Er is een nieuwe versie van {APP_NAME} beschikbaar! Klik hier voor details.", + "UPDATE_AVAILABLE_TITLE" : "Update beschikbaar", + "UPDATE_MESSAGE" : "Hey, er is een nieuwe versie van {APP_NAME} beschikbaar. Hier zijn een aantal van de nieuwe functies:", "GET_IT_NOW" : "Haal het nu!", - "PROJECT_SETTINGS_TITLE" : "Project Instellingen voor: {0}", - "PROJECT_SETTING_BASE_URL" : "Live Voorbeeld Start URL", - "PROJECT_SETTING_BASE_URL_HINT" : "Om een locale server te gebruiken, voor een url in zoals http://localhost:8000/", + "PROJECT_SETTINGS_TITLE" : "Project instellingen voor: {0}", + "PROJECT_SETTING_BASE_URL" : "Live voorbeeld begin URL", + "PROJECT_SETTING_BASE_URL_HINT" : "Om als locale server te gebruiken, voer een url in als http://localhost:8000/", "BASEURL_ERROR_INVALID_PROTOCOL" : "Het {0} protocol wordt niet ondersteund door Live Voorbeeld—gebruik http: of https: .", "BASEURL_ERROR_SEARCH_DISALLOWED" : "De start URL kan geen zoekparameters bevatten zoals \"{0}\".", "BASEURL_ERROR_HASH_DISALLOWED" : "De start URL kan geen hashes bevatten zoals \"{0}\".", "BASEURL_ERROR_INVALID_CHAR" : "Speciale karakters zoals '{0}' moeten %-geëncodeerd zijn.", - "BASEURL_ERROR_UNKNOWN_ERROR" : "Onbekende fout bij het parsen van de Start URL", + "BASEURL_ERROR_UNKNOWN_ERROR" : "Onbekende fout bij het parsen van de begin URL", // Extension Management strings - "INSTALL" : "Installeer", + "INSTALL" : "Installeren", "UPDATE" : "Update", "REMOVE" : "Verwijder", "OVERWRITE" : "Overschrijf", - "CANT_REMOVE_DEV" : "Uitbreidings in de \"dev\" map moeten manueel verwijderd worden.", + "CANT_REMOVE_DEV" : "Uitbreidingen in de \"dev\" map moeten met de hand verwijderd worden.", "CANT_UPDATE" : "De update is niet compatibel met deze versie van {APP_NAME}.", - "INSTALL_EXTENSION_TITLE" : "Installeer Uitbreiding", - "UPDATE_EXTENSION_TITLE" : "Update Uitbreiding", + "INSTALL_EXTENSION_TITLE" : "Installeer uitbreiding", + "UPDATE_EXTENSION_TITLE" : "Update uitbreiding", "INSTALL_EXTENSION_LABEL" : "Uitbreiding URL", "INSTALL_EXTENSION_HINT" : "URL van het zip bestand of de GitHup repo van de uitbreiding", "INSTALLING_FROM" : "Bezig met installeren van uitbreiding van {0}\u2026", "INSTALL_SUCCEEDED" : "Installatie succesvol!", - "INSTALL_FAILED" : "Installatie gefaald.", + "INSTALL_FAILED" : "Installatie mislukt.", "CANCELING_INSTALL" : "Bezig met annuleren\u2026", "CANCELING_HUNG" : "Het annuleren van de installatie duurt lang. Een intern probleem kan zijn opgetreden.", "INSTALL_CANCELED" : "Installatie geannuleerd.", // These must match the error codes in ExtensionsDomain.Errors.* : "INVALID_ZIP_FILE" : "De gedownloade inhoud is geen geldig zip bestand.", - "INVALID_PACKAGE_JSON" : "Het package.json bestand is niet geldig (fout was: {0}).", + "INVALID_PACKAGE_JSON" : "Het package.json bestand is niet geldig (Fout: {0}).", "MISSING_PACKAGE_NAME" : "Het package.json specifieert geen pakket naam.", "BAD_PACKAGE_NAME" : "{0} is een ongeldige pakket naam.", "MISSING_PACKAGE_VERSION" : "Het package.json bestand specifieert geen geldige pakket versie.", @@ -362,15 +362,15 @@ define({ "EXTENSION_OLDER_VERSION" : "Dit pakket is versie {0} dewelke ouder is dan de op dit moment geïnstalleerde ({1}). Overschrijf de bestaande installatie?", "DOWNLOAD_ID_IN_USE" : "Interne fout: download ID is reeds in gebruik.", "NO_SERVER_RESPONSE" : "Kan niet verbinden met de server.", - "BAD_HTTP_STATUS" : "Bestand niet gevonden op server (HTTP {0}).", - "CANNOT_WRITE_TEMP" : "Onmogelijk om download op te slaan naar tijdelijk bestand.", + "BAD_HTTP_STATUS" : "Bestand niet worden gevonden op server (HTTP {0}).", + "CANNOT_WRITE_TEMP" : "Onmogelijk om het gedownloade bestand op te slaan naar een tijdelijk bestand.", "ERROR_LOADING" : "De uitbreiding ondervond een probleem bij het opstarten.", - "MALFORMED_URL" : "De URL is ongeldig. Controleer of ze correct werd ingevoerd.", + "MALFORMED_URL" : "De URL is ongeldig. Controleer of deze correct is ingevoerd.", "UNSUPPORTED_PROTOCOL" : "De URL moet een http of https URL zijn.", "UNKNOWN_ERROR" : "Onbekende interne fout.", // For NOT_FOUND_ERR, see generic strings above "EXTENSION_MANAGER_TITLE" : "Uitbreidingbeheer", - "EXTENSION_MANAGER_ERROR_LOAD" : "Onmogelijk om toegang te verkrijgen tot het uitbreidingen register. Probeer later opnieuw.", + "EXTENSION_MANAGER_ERROR_LOAD" : "Er is momenteel geen toegang verkrijgbaar tot het uitbreidingen register. Probeer later opnieuw.", "INSTALL_FROM_URL" : "Installeer van URL\u2026", "EXTENSION_AUTHOR" : "Auteur", "EXTENSION_DATE" : "Datum", @@ -384,22 +384,22 @@ define({ "EXTENSION_UPDATE_INSTALLED" : "Deze uitbreiding is gedownload en zal geïnstalleerd worden wanneer je {APP_NAME} stopt.", "EXTENSION_SEARCH_PLACEHOLDER" : "Zoek", "EXTENSION_MORE_INFO_LINK" : "Meer", - "BROWSE_EXTENSIONS" : "Blader door Uitbreidingen", - "EXTENSION_MANAGER_REMOVE" : "Verwijder Uitbreiding", + "BROWSE_EXTENSIONS" : "Blader door uitbreidingen", + "EXTENSION_MANAGER_REMOVE" : "Verwijder uitbreiding", "EXTENSION_MANAGER_REMOVE_ERROR" : "Onmogelijk om een of meerdere uitbreidingen te verwijderen: {0}. {APP_NAME} zal nog steeds stoppen.", - "EXTENSION_MANAGER_UPDATE" : "Update Uitbreiding", + "EXTENSION_MANAGER_UPDATE" : "Update uitbreiding", "EXTENSION_MANAGER_UPDATE_ERROR" : "Onmogelijk om een of meerdere uitbreidingen te updaten: {0}. {APP_NAME} zal nog steeds stoppen.", "MARKED_FOR_REMOVAL" : "Aangeduid voor verwijdering", "UNDO_REMOVE" : "Herstel", "MARKED_FOR_UPDATE" : "Aangeduid voor update", "UNDO_UPDATE" : "Herstel", "CHANGE_AND_QUIT_TITLE" : "Wijzig Uitbreidingen", - "CHANGE_AND_QUIT_MESSAGE" : "Om de aangeduidde uitbreiding te updaten of te verwijderen, moet je {APP_NAME} stoppen en herstarten. Je zal gevraagd worden alle onbewaarde wijzigingen op te slaan.", - "REMOVE_AND_QUIT" : "Verwijder Uitbreidingen en stop", - "CHANGE_AND_QUIT" : "Wijzig Uitbreidingen en Stop", - "UPDATE_AND_QUIT" : "Update Uitbreidingen en Stop", - "EXTENSION_NOT_INSTALLED" : "Kon de uitbreiding {0} niet verwijderen omdat ze niet was geïnstalleerd", - "NO_EXTENSIONS" : "Nog geen uitbreidingen geïnstalleerd.
Klik op de Beschikbaar tab hierboven om te starten.", + "CHANGE_AND_QUIT_MESSAGE" : "Om de aangeduidde uitbreiding te updaten of te verwijderen, moet je {APP_NAME} stoppen en herstarten. Er zal gevraagd worden alle onbewaarde wijzigingen op te slaan.", + "REMOVE_AND_QUIT" : "Verwijder uitbreidingen en afsluiten", + "CHANGE_AND_QUIT" : "Wijzig Uitbreidingen en afsluiten", + "UPDATE_AND_QUIT" : "Update Uitbreidingen en afsluiten", + "EXTENSION_NOT_INSTALLED" : "Kon de uitbreiding {0} niet verwijderen omdat deze niet is geïnstalleerd", + "NO_EXTENSIONS" : "Geen uitbreidingen geïnstalleerd.
Klik op de Beschikbaar tab hierboven om te starten.", "NO_EXTENSION_MATCHES" : "Geen uitbreidingen komen overeen met je zoekopdracht.", "REGISTRY_SANITY_CHECK_WARNING" : "Wees voorzichtig bij het installeren van uitbreidingen van een onbekende bron.", "EXTENSIONS_INSTALLED_TITLE" : "Geïnstalleerd", @@ -415,45 +415,46 @@ define({ // extensions/default/DebugCommands "DEBUG_MENU" : "Debug", - "CMD_SHOW_DEV_TOOLS" : "Toon Developer Tools", - "CMD_REFRESH_WINDOW" : "Herlaad {APP_NAME}", - "CMD_NEW_BRACKETS_WINDOW" : "Nieuw {APP_NAME} Venster", - "CMD_SWITCH_LANGUAGE" : "Wijzig Taal", - "CMD_RUN_UNIT_TESTS" : "Start Testen", + "CMD_SHOW_DEV_TOOLS" : "Tools weergeven voor ontwikkelaars", + "CMD_REFRESH_WINDOW" : "Opnieuw laden {APP_NAME}", + "CMD_NEW_BRACKETS_WINDOW" : "Nieuw {APP_NAME} venster", + "CMD_SWITCH_LANGUAGE" : "Wijzig taal", + "CMD_RUN_UNIT_TESTS" : "Start testen", "CMD_SHOW_PERF_DATA" : "Toon Performantie Data", "CMD_ENABLE_NODE_DEBUGGER" : "Schakel Node Debugger in", "CMD_LOG_NODE_STATE" : "Log Node Status naar Console", "CMD_RESTART_NODE" : "Herstart Node", - "LANGUAGE_TITLE" : "Wijzig Taal", + "LANGUAGE_TITLE" : "Wijzig taal", "LANGUAGE_MESSAGE" : "Taal:", - "LANGUAGE_SUBMIT" : "Herlaad {APP_NAME}", - "LANGUAGE_CANCEL" : "Annuleer", - "LANGUAGE_SYSTEM_DEFAULT" : "Systeem Standaard", + "LANGUAGE_SUBMIT" : "{APP_NAME} opnieuw laden", + "LANGUAGE_CANCEL" : "Annuleren", + "LANGUAGE_SYSTEM_DEFAULT" : "Systeem voorkeuren", // extensions/default/InlineColorEditor - "COLOR_EDITOR_CURRENT_COLOR_SWATCH_TIP" : "Huidige Kleur", - "COLOR_EDITOR_ORIGINAL_COLOR_SWATCH_TIP" : "Originele Kleur", - "COLOR_EDITOR_RGBA_BUTTON_TIP" : "RGBa Formaat", - "COLOR_EDITOR_HEX_BUTTON_TIP" : "Hex Formaat", - "COLOR_EDITOR_HSLA_BUTTON_TIP" : "HSLa Formaat", + "COLOR_EDITOR_CURRENT_COLOR_SWATCH_TIP" : "Huidige kleur", + "COLOR_EDITOR_ORIGINAL_COLOR_SWATCH_TIP" : "Originele kleur", + "COLOR_EDITOR_RGBA_BUTTON_TIP" : "RGBa formaat", + "COLOR_EDITOR_HEX_BUTTON_TIP" : "Hex formaat", + "COLOR_EDITOR_HSLA_BUTTON_TIP" : "HSLa formaat", "COLOR_EDITOR_USED_COLOR_TIP_SINGULAR" : "{0} ({1} keer gebruikt)", - "COLOR_EDITOR_USED_COLOR_TIP_PLURAL" : "{0} ({1} keren gebruikt)", + "COLOR_EDITOR_USED_COLOR_TIP_PLURAL" : "{0} ({1} keer gebruikt)", // extensions/default/JavaScriptCodeHints - "CMD_JUMPTO_DEFINITION" : "Ga naar Definitie", - "CMD_SHOW_PARAMETER_HINT" : "Toon Parameter Hint", + "CMD_JUMPTO_DEFINITION" : "Ga naar definitie", + "CMD_SHOW_PARAMETER_HINT" : "Toon parameter Hint", "NO_ARGUMENTS" : "", // extensions/default/JSLint "JSLINT_NAME" : "JSLint", // extensions/default/QuickView - "CMD_ENABLE_QUICK_VIEW" : "Snel bekijken bij Muis Over", + "CMD_ENABLE_QUICK_VIEW" : "Snel bekijken bij muis over", // extensions/default/RecentProjects - "CMD_TOGGLE_RECENT_PROJECTS" : "Recente Projecten", + "CMD_TOGGLE_RECENT_PROJECTS" : "Recente projecten", // extensions/default/WebPlatformDocs "DOCS_MORE_LINK" : "Lees meer" }); +/* Last translated for 752856d58d2e9dde14e1af6be615bb7080727b7a */ diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 9e4a11045..d4048948d 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -40,15 +40,17 @@ define({ "UNSUPPORTED_ENCODING_ERR" : "{APP_NAME} currently only supports UTF-8 encoded text files.", "FILE_EXISTS_ERR" : "The file or directory already exists.", "FILE" : "file", + "FILE_TITLE" : "File", "DIRECTORY" : "directory", + "DIRECTORY_TITLE" : "Directory", "DIRECTORY_NAMES_LEDE" : "Directory names", "FILENAMES_LEDE" : "Filenames", - "FILENAME" : "filename", - "DIRECTORY_NAME" : "directory name", + "FILENAME" : "Filename", + "DIRECTORY_NAME" : "Directory Name", // Project error strings - "ERROR_LOADING_PROJECT" : "Error loading project", + "ERROR_LOADING_PROJECT" : "Error Loading Project", "OPEN_DIALOG_ERROR" : "An error occurred when showing the open file dialog. (error {0})", "REQUEST_NATIVE_FILE_SYSTEM_ERROR" : "An error occurred when trying to load the directory {0}. (error {1})", "READ_DIRECTORY_ENTRIES_ERROR" : "An error occurred when reading the contents of the directory {0}. (error {1})", @@ -61,10 +63,10 @@ define({ "ERROR_RELOADING_FILE" : "An error occurred when trying to reload the file {0}. {1}", "ERROR_SAVING_FILE_TITLE" : "Error Saving File", "ERROR_SAVING_FILE" : "An error occurred when trying to save the file {0}. {1}", - "ERROR_RENAMING_FILE_TITLE" : "Error Renaming File", - "ERROR_RENAMING_FILE" : "An error occurred when trying to rename the file {0}. {1}", - "ERROR_DELETING_FILE_TITLE" : "Error Deleting File", - "ERROR_DELETING_FILE" : "An error occurred when trying to delete the file {0}. {1}", + "ERROR_RENAMING_FILE_TITLE" : "Error Renaming {0}", + "ERROR_RENAMING_FILE" : "An error occurred when trying to rename the {2} {0}. {1}", + "ERROR_DELETING_FILE_TITLE" : "Error Deleting {0}", + "ERROR_DELETING_FILE" : "An error occurred when trying to delete the {2} {0}. {1}", "INVALID_FILENAME_TITLE" : "Invalid {0}", "INVALID_FILENAME_MESSAGE" : "{0} cannot use any system reserved words, end with dots (.) or use any of the following characters: {1}", "ENTRY_WITH_SAME_NAME_EXISTS" : "A file or directory with the name {0} already exists.", @@ -183,7 +185,7 @@ define({ "REPLACE_IN_FILES_ERRORS_TITLE" : "Replace Errors", "REPLACE_IN_FILES_ERRORS" : "The following files weren't modified because they changed after the search or couldn't be written.", - "ERROR_FETCHING_UPDATE_INFO_TITLE" : "Error getting update info", + "ERROR_FETCHING_UPDATE_INFO_TITLE" : "Error Getting Update Info", "ERROR_FETCHING_UPDATE_INFO_MSG" : "There was a problem getting the latest update information from the server. Please make sure you are connected to the internet and try again.", // File exclusion filters @@ -446,6 +448,8 @@ define({ "CANCELING_INSTALL" : "Canceling\u2026", "CANCELING_HUNG" : "Canceling the install is taking a long time. An internal error may have occurred.", "INSTALL_CANCELED" : "Installation canceled.", + "VIEW_COMPLETE_DESCRIPTION" : "View complete description", + "VIEW_TRUNCATED_DESCRIPTION" : "View truncated description", // These must match the error codes in ExtensionsDomain.Errors.* : "INVALID_ZIP_FILE" : "The downloaded content is not a valid zip file.", "INVALID_PACKAGE_JSON" : "The package.json file is not valid (error was: {0}).", @@ -471,7 +475,11 @@ define({ // For NOT_FOUND_ERR, see generic strings above "EXTENSION_MANAGER_TITLE" : "Extension Manager", "EXTENSION_MANAGER_ERROR_LOAD" : "Unable to access the extension registry. Please try again later.", + "INSTALL_EXTENSION_DRAG" : "Drag .zip in here or", + "INSTALL_EXTENSION_DROP" : "Drop .zip to install", + "INSTALL_EXTENSION_DROP_ERROR" : "Install/Update aborted due to the following errors:", "INSTALL_FROM_URL" : "Install from URL\u2026", + "INSTALL_EXTENSION_VALIDATING" : "Validating\u2026", "EXTENSION_AUTHOR" : "Author", "EXTENSION_DATE" : "Date", "EXTENSION_INCOMPATIBLE_NEWER" : "This extension requires a newer version of {APP_NAME}.", diff --git a/src/project/ProjectManager.js b/src/project/ProjectManager.js index 91e30de34..320cb8242 100644 --- a/src/project/ProjectManager.js +++ b/src/project/ProjectManager.js @@ -115,6 +115,22 @@ define(function (require, exports, module) { */ var SETTINGS_FILENAME = "." + PreferencesManager.SETTINGS_FILENAME; + /** + * @const + * @private + * Error context to show the correct error message + * @type {int} + */ + var ERR_TYPE_CREATE = 1, + ERR_TYPE_CREATE_EXISTS = 2, + ERR_TYPE_RENAME = 3, + ERR_TYPE_DELETE = 4, + ERR_TYPE_LOADING_PROJECT = 5, + ERR_TYPE_LOADING_PROJECT_NATIVE = 6, + ERR_TYPE_MAX_FILES = 7, + ERR_TYPE_OPEN_DIALOG = 8, + ERR_TYPE_INVALID_FILENAME = 9; + /** * @private * Reference to the tree control container div. Initialized by @@ -764,6 +780,62 @@ define(function (require, exports, module) { return Async.withTimeout(result.promise(), 1000); } + function _showErrorDialog(errType, isFolder, error, path) { + var titleType = isFolder ? Strings.DIRECTORY_TITLE : Strings.FILE_TITLE, + entryType = isFolder ? Strings.DIRECTORY : Strings.FILE, + title, + message; + path = StringUtils.breakableUrl(path); + + switch (errType) { + case ERR_TYPE_CREATE: + title = StringUtils.format(Strings.ERROR_CREATING_FILE_TITLE, titleType); + message = StringUtils.format(Strings.ERROR_CREATING_FILE, entryType, path, error); + break; + case ERR_TYPE_CREATE_EXISTS: + title = StringUtils.format(Strings.INVALID_FILENAME_TITLE, titleType); + message = StringUtils.format(Strings.ENTRY_WITH_SAME_NAME_EXISTS, path); + break; + case ERR_TYPE_RENAME: + title = StringUtils.format(Strings.ERROR_RENAMING_FILE_TITLE, titleType); + message = StringUtils.format(Strings.ERROR_RENAMING_FILE, path, error, entryType); + break; + case ERR_TYPE_DELETE: + title = StringUtils.format(Strings.ERROR_DELETING_FILE_TITLE, titleType); + message = StringUtils.format(Strings.ERROR_DELETING_FILE, path, error, entryType); + break; + case ERR_TYPE_LOADING_PROJECT: + title = Strings.ERROR_LOADING_PROJECT; + message = StringUtils.format(Strings.READ_DIRECTORY_ENTRIES_ERROR, path, error); + break; + case ERR_TYPE_LOADING_PROJECT_NATIVE: + title = Strings.ERROR_LOADING_PROJECT; + message = StringUtils.format(Strings.REQUEST_NATIVE_FILE_SYSTEM_ERROR, path, error); + break; + case ERR_TYPE_MAX_FILES: + title = Strings.ERROR_MAX_FILES_TITLE; + message = Strings.ERROR_MAX_FILES; + break; + case ERR_TYPE_OPEN_DIALOG: + title = Strings.ERROR_LOADING_PROJECT; + message = StringUtils.format(Strings.OPEN_DIALOG_ERROR, error); + break; + case ERR_TYPE_INVALID_FILENAME: + title = StringUtils.format(Strings.INVALID_FILENAME_TITLE, isFolder ? Strings.DIRECTORY_NAME : Strings.FILENAME); + message = StringUtils.format(Strings.INVALID_FILENAME_MESSAGE, isFolder ? Strings.DIRECTORY_NAMES_LEDE : Strings.FILENAMES_LEDE, error); + break; + } + + if (title && message) { + return Dialogs.showModalDialog( + DefaultDialogs.DIALOG_ID_ERROR, + title, + message + ); + } + return null; + } + /** * @private * See shouldShow @@ -945,15 +1017,7 @@ define(function (require, exports, module) { // Fetch dirEntry's contents dirEntry.getContents(function (err, contents, stats, statsErrs) { if (err) { - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_LOADING_PROJECT, - StringUtils.format( - Strings.READ_DIRECTORY_ENTRIES_ERROR, - StringUtils.breakableUrl(dirEntry.fullPath), - err - ) - ); + _showErrorDialog(ERR_TYPE_LOADING_PROJECT, null, err, dirEntry.fullPath); // Reject the render promise so we can move on. deferred.reject(); } else { @@ -1049,25 +1113,13 @@ define(function (require, exports, module) { return updateWelcomeProjectPath(PreferencesManager.getViewState("projectPath")); } - /** - * Error dialog when max files in index is hit - * @return {Dialog} - */ - function _showMaxFilesDialog() { - return Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_MAX_FILES_TITLE, - Strings.ERROR_MAX_FILES - ); - } - function _watchProjectRoot(rootPath) { FileSystem.on("change", _fileSystemChange); FileSystem.on("rename", _fileSystemRename); FileSystem.watch(FileSystem.getDirectoryForPath(rootPath), _shouldShowName, function (err) { if (err === FileSystemError.TOO_MANY_ENTRIES) { - _showMaxFilesDialog(); + _showErrorDialog(ERR_TYPE_MAX_FILES); } else if (err) { console.error("Error watching project root: ", rootPath, err); } @@ -1200,7 +1252,6 @@ define(function (require, exports, module) { if (exists) { var projectRootChanged = (!_projectRoot || !rootEntry) || _projectRoot.fullPath !== rootEntry.fullPath; - var i; // Success! var perfTimerName = PerfUtils.markStart("Load Project: " + rootPath); @@ -1246,31 +1297,24 @@ define(function (require, exports, module) { PerfUtils.addMeasurement(perfTimerName); }); } else { - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_LOADING_PROJECT, - StringUtils.format( - Strings.REQUEST_NATIVE_FILE_SYSTEM_ERROR, - StringUtils.breakableUrl(rootPath), - err || FileSystemError.NOT_FOUND - ) - ).done(function () { - // Reset _projectRoot to null so that the following _loadProject call won't - // run the 'beforeProjectClose' event a second time on the original project, - // which is now partially torn down (see #6574). - _projectRoot = null; - - // The project folder stored in preference doesn't exist, so load the default - // project directory. - // TODO (issue #267): When Brackets supports having no project directory - // defined this code will need to change - _loadProject(_getWelcomeProjectPath()).always(function () { - // Make sure not to reject the original deferred until the fallback - // project is loaded, so we don't violate expectations that there is always - // a current project before continuing after _loadProject(). - result.reject(); + _showErrorDialog(ERR_TYPE_LOADING_PROJECT_NATIVE, null, rootPath, err || FileSystemError.NOT_FOUND) + .done(function () { + // Reset _projectRoot to null so that the following _loadProject call won't + // run the 'beforeProjectClose' event a second time on the original project, + // which is now partially torn down (see #6574). + _projectRoot = null; + + // The project folder stored in preference doesn't exist, so load the default + // project directory. + // TODO (issue #267): When Brackets supports having no project directory + // defined this code will need to change + _loadProject(_getWelcomeProjectPath()).always(function () { + // Make sure not to reject the original deferred until the fallback + // project is loaded, so we don't violate expectations that there is always + // a current project before continuing after _loadProject(). + result.reject(); + }); }); - }); } }); } @@ -1522,11 +1566,7 @@ define(function (require, exports, module) { result.reject(); } } else { - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_LOADING_PROJECT, - StringUtils.format(Strings.OPEN_DIALOG_ERROR, err) - ); + _showErrorDialog(ERR_TYPE_OPEN_DIALOG, null, err); result.reject(); } }); @@ -1565,11 +1605,7 @@ define(function (require, exports, module) { // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx if ((filename.search(new RegExp("[" + _invalidChars + "]+")) !== -1) || filename.match(_illegalFilenamesRegEx)) { - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - StringUtils.format(Strings.INVALID_FILENAME_TITLE, isFolder ? Strings.DIRECTORY_NAME : Strings.FILENAME), - StringUtils.format(Strings.INVALID_FILENAME_MESSAGE, isFolder ? Strings.DIRECTORY_NAMES_LEDE : Strings.FILENAMES_LEDE, _invalidChars) - ); + _showErrorDialog(ERR_TYPE_INVALID_FILENAME, isFolder, _invalidChars); return false; } return true; @@ -1694,27 +1730,15 @@ define(function (require, exports, module) { _createNode($baseDirNode, null, _entryToJSON(entry), true, true); }; - var errorCallback = function (error, entry) { - var titleType = isFolder ? Strings.DIRECTORY_NAME : Strings.FILENAME, - entryType = isFolder ? Strings.DIRECTORY : Strings.FILE; + var errorCallback = function (error) { if (error === FileSystemError.ALREADY_EXISTS) { - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - StringUtils.format(Strings.INVALID_FILENAME_TITLE, titleType), - StringUtils.format(Strings.ENTRY_WITH_SAME_NAME_EXISTS, - StringUtils.breakableUrl(data.rslt.name)) - ); + _showErrorDialog(ERR_TYPE_CREATE_EXISTS, isFolder, null, data.rslt.name); } else { var errString = error === FileSystemError.NOT_WRITABLE ? Strings.NO_MODIFICATION_ALLOWED_ERR : StringUtils.format(Strings.GENERIC_ERROR, error); - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - StringUtils.format(Strings.ERROR_CREATING_FILE_TITLE, entryType), - StringUtils.format(Strings.ERROR_CREATING_FILE, entryType, - StringUtils.breakableUrl(data.rslt.name), errString) - ); + _showErrorDialog(ERR_TYPE_CREATE, isFolder, errString, data.rslt.name); } errorCleanup(); @@ -1722,10 +1746,10 @@ define(function (require, exports, module) { var newItemPath = baseDirEntry.fullPath + data.rslt.name; - FileSystem.resolve(newItemPath, function (err, item) { + FileSystem.resolve(newItemPath, function (err) { if (!err) { // Item already exists, fail with error - errorCallback(FileSystemError.ALREADY_EXISTS, item); + errorCallback(FileSystemError.ALREADY_EXISTS); } else { if (isFolder) { var directory = FileSystem.getDirectoryForPath(newItemPath); @@ -1820,17 +1844,11 @@ define(function (require, exports, module) { result.resolve(); } else { // Show an error alert - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_ERROR, - Strings.ERROR_RENAMING_FILE_TITLE, - StringUtils.format( - Strings.ERROR_RENAMING_FILE, - StringUtils.breakableUrl(newName), - err === FileSystemError.ALREADY_EXISTS ? + var errString = err === FileSystemError.ALREADY_EXISTS ? Strings.FILE_EXISTS_ERR : - FileUtils.getFileErrorString(err) - ) - ); + FileUtils.getFileErrorString(err); + + _showErrorDialog(ERR_TYPE_RENAME, isFolder, errString, newName); result.reject(err); } }); @@ -2005,16 +2023,7 @@ define(function (require, exports, module) { _deleteTreeNode(entry); result.resolve(); } else { - // Show an error alert - Dialogs.showModalDialog( - Dialogs.DIALOG_ID_ERROR, - Strings.ERROR_DELETING_FILE_TITLE, - StringUtils.format( - Strings.ERROR_DELETING_FILE, - _.escape(entry.fullPath), - FileUtils.getFileErrorString(err) - ) - ); + _showErrorDialog(ERR_TYPE_DELETE, entry.isDirectory, FileUtils.getFileErrorString(err), entry.fullPath); result.reject(err); } diff --git a/src/styles/brackets.less b/src/styles/brackets.less index 57ed4c35d..71597e0aa 100644 --- a/src/styles/brackets.less +++ b/src/styles/brackets.less @@ -1652,6 +1652,65 @@ label input { font-size: 1.01em; } +/* Extension Manager */ +#install-drop-zone { + background-color: transparent; + box-shadow: initial; + font-weight: normal; + border-style: dashed; + position: relative; +} + +#install-drop-zone-mask { + position: absolute; + top: -1px; + left: -1px; + + padding: 1px; + width: 100%; + height: 100%; + display: none; + + cursor: copy; +} + +#install-drop-zone.drop #install-drop-zone-mask { + display: block; +} + +#install-drop-zone.drop { + background: @tc-call-to-action; + box-shadow: initial; + font-weight: normal; + border: 1px solid @tc-call-to-action; + color: @tc-call-to-action-text; + text-shadow: none; +} + +.install-drag-message { + display: none; +} + +.install-drop-message { + display: none; +} + +.install-validating-message { + display: none; +} + +#install-drop-zone.drag .install-drag-message { + display: inline; +} + +#install-drop-zone.drop .install-drop-message { + display: inline; +} + +#install-drop-zone.validating .install-validating-message { + display: inline; +} + .theme-settings td { padding: 2px; } diff --git a/src/styles/brackets_patterns_override.less b/src/styles/brackets_patterns_override.less index 64eaf4955..5775faa17 100644 --- a/src/styles/brackets_patterns_override.less +++ b/src/styles/brackets_patterns_override.less @@ -972,9 +972,6 @@ a[href^="http"] { .user-select(text); cursor: text; } - .ext-keywords { - color: @tc-input-placeholder-text; - } .ext-translated { color: @tc-input-placeholder-text; } diff --git a/src/utils/StringUtils.js b/src/utils/StringUtils.js index 3770f47ff..4b59316c6 100644 --- a/src/utils/StringUtils.js +++ b/src/utils/StringUtils.js @@ -198,6 +198,27 @@ define(function (require, exports, module) { return returnVal; } + /** + * Truncate strings to specified length. + * @param {string} str Text to be truncated. + * @param {number} len Length to which text should be limited. + * @return {string} Returns truncated text only if it was changed. + */ + function truncate(str, len) { + // Truncate the description if it is too long + if (str.length > len) { + str = str.substr(0, len); + + // To prevent awkward addition of ellipsis, try to truncate + // at the end of the last whole word + var lastSpaceChar = str.lastIndexOf(" "); + if (lastSpaceChar < len && lastSpaceChar > -1) { + str = str.substr(0, lastSpaceChar); + } + return str; + } + } + // Define public API exports.format = format; exports.htmlEscape = htmlEscape; @@ -209,4 +230,5 @@ define(function (require, exports, module) { exports.breakableUrl = breakableUrl; exports.endsWith = endsWith; exports.prettyPrintBytes = prettyPrintBytes; + exports.truncate = truncate; }); diff --git a/test/spec/ExtensionManager-test.js b/test/spec/ExtensionManager-test.js index 13aef10d7..207f81d4f 100644 --- a/test/spec/ExtensionManager-test.js +++ b/test/spec/ExtensionManager-test.js @@ -690,7 +690,7 @@ define(function (require, exports, module) { }); runs(function () { expect(file.unlink).not.toHaveBeenCalled(); - expect(Package.installUpdate).toHaveBeenCalledWith(filename, id); + expect(Package.installUpdate).toHaveBeenCalledWith(filename, id, undefined); }); }); @@ -770,8 +770,7 @@ define(function (require, exports, module) { // Simple fields [item.metadata.version, - item.metadata.author && item.metadata.author.name, - item.metadata.description] + item.metadata.author && item.metadata.author.name] .forEach(function (value) { if (value) { expect(view).toHaveText(value); @@ -782,7 +781,7 @@ define(function (require, exports, module) { } // Array-valued fields - [item.metadata.keywords, item.metadata.categories].forEach(function (arr) { + [item.metadata.categories].forEach(function (arr) { if (arr) { arr.forEach(function (value) { expect(view).toHaveText(value); @@ -793,6 +792,33 @@ define(function (require, exports, module) { }); }); + it("should display original description", function () { + setupViewWithMockData(ExtensionManagerViewModel.RegistryViewModel); + runs(function () { + _.forEach(mockRegistry, function (item) { + if (item.metadata.description) { + if (StringUtils.truncate(item.metadata.description, 200) === undefined) { + expect(view).toHaveText(item.metadata.description); + } + } + }); + }); + }); + + it("should display shortened description", function () { + setupViewWithMockData(ExtensionManagerViewModel.RegistryViewModel); + runs(function () { + _.forEach(mockRegistry, function (item) { + if (item.metadata.description) { + var shortDescription = StringUtils.truncate(item.metadata.description, 200); + if (shortDescription !== undefined) { + expect(view).toHaveText(shortDescription); + } + } + }); + }); + }); + it("should display owner even for installed items", function () { ExtensionManager._setExtensions(JSON.parse(mockExtensionList)); setupViewWithMockData(ExtensionManagerViewModel.InstalledViewModel); @@ -1499,7 +1525,7 @@ define(function (require, exports, module) { }); waitsFor(function () { return didReload; }, "mock reload"); runs(function () { - expect(Package.installUpdate).toHaveBeenCalledWith(filename, id); + expect(Package.installUpdate).toHaveBeenCalledWith(filename, id, undefined); expect(didClose).toBe(true); expect(didReload).toBe(true); });