Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,8 @@ define(function (require, exports, module) {
$target.is("input[type=number]") ||
$target.is("input[type=password]") ||
$target.is("input:not([type])") || // input with no type attribute defaults to text
$target.is("textarea");
$target.is("textarea") ||
$target.is("select");

if (!isTextField) {
e.preventDefault();
Expand Down
32 changes: 30 additions & 2 deletions src/document/Document.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ define(function (require, exports, module) {
* @type {FileUtils.LINE_ENDINGS_CRLF|FileUtils.LINE_ENDINGS_LF}
*/
Document.prototype._lineEndings = null;

/**
* Whether this document's language was forced (manually selected) or not.
* If true, the language will not change when _updateLanguage() is called.
* @type {boolean}
*/
Document.prototype._languageWasForced = false;

/** Add a ref to keep this Document alive */
Document.prototype.addRef = function () {
Expand Down Expand Up @@ -423,14 +430,35 @@ define(function (require, exports, module) {
Document.prototype.getLanguage = function () {
return this.language;
};

/**
* Overrides the default language of this document and sets it to the given
* language.
* @param {?Language} language The language to be set for this document; if
* null, the language will be set back to the default.
*/
Document.prototype.forceLanguage = function (language) {
if (language) {
var oldLanguage = this.language;
this._languageWasForced = true;
this.language = language;
$(this).triggerHandler("languageChanged", [oldLanguage, this.language]);
} else { // if language was null, reset to default language
this._languageWasForced = false;
this._updateLanguage();
}
};

/**
* Updates the language according to the file extension
* Updates the language according to the file extension. If the current
* language was forced (set manually by user), don't change it.
*/
Document.prototype._updateLanguage = function () {
if (this._languageWasForced) {
return;
}
var oldLanguage = this.language;
this.language = LanguageManager.getLanguageForPath(this.file.fullPath);

if (oldLanguage && oldLanguage !== this.language) {
$(this).triggerHandler("languageChanged", [oldLanguage, this.language]);
}
Expand Down
80 changes: 69 additions & 11 deletions src/editor/EditorStatusBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,20 @@ define(function (require, exports, module) {
"use strict";

// Load dependent modules
var AppInit = require("utils/AppInit"),
EditorManager = require("editor/EditorManager"),
Editor = require("editor/Editor").Editor,
KeyEvent = require("utils/KeyEvent"),
StatusBar = require("widgets/StatusBar"),
Strings = require("strings"),
StringUtils = require("utils/StringUtils");
var AppInit = require("utils/AppInit"),
CollectionUtils = require("utils/CollectionUtils"),
DefaultDialogs = require("widgets/DefaultDialogs"),
Dialogs = require("widgets/Dialogs"),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dialogs imports are unused now

EditorManager = require("editor/EditorManager"),
Editor = require("editor/Editor").Editor,
KeyEvent = require("utils/KeyEvent"),
LanguageManager = require("language/LanguageManager"),
StatusBar = require("widgets/StatusBar"),
Strings = require("strings"),
StringUtils = require("utils/StringUtils");

/* StatusBar indicators */
var $languageInfo,
var $languageSelect,
$cursorInfo,
$fileInfo,
$indentType,
Expand All @@ -50,7 +54,11 @@ define(function (require, exports, module) {


function _updateLanguageInfo(editor) {
$languageInfo.text(editor.document.getLanguage().getName());
var lang = editor.document.getLanguage();
$languageSelect.empty();
$("<option />").val(lang.getId()).text(lang.getName())
.appendTo($languageSelect);
$languageSelect.val(lang.getId());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second val() call seems unneeded

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops sorry -- it's not

}

function _updateFileInfo(editor) {
Expand Down Expand Up @@ -147,8 +155,52 @@ define(function (require, exports, module) {
}
}

/**
* Setup and populate a custom <select> dropdown for switching the language
* mode for the given document.
* @param {!Document} document The document for which to switch the language
*/
function _setupLanguageSelect(document) {
// Lazy load the languages in the dropdown to avoid having to receive
// updates from LanguageManager (not to mention unnecessary processing
// since most users will not need to manually set the language).
var languages = LanguageManager.getLanguages();

// lock width of <select>, else it changes when it's populated
$languageSelect.css("width", $languageSelect.css("width"));

// fill the dropbown using the languages list
$languageSelect.empty();
CollectionUtils.forEach(languages, function (lang) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've switched to _.forEach() in the interim since this PR was posted

$("<option />").val(lang.getId()).text(lang.getName())
.appendTo($languageSelect);
});
$languageSelect.val(document.getLanguage().getId());

// sort dropdown alphabetically
$languageSelect.html($languageSelect.find("option").sort(
function (a, b) {
return a.text.toLowerCase().localeCompare(b.text.toLowerCase());
}
));

// set change handler for select box
$languageSelect.on("change", function () {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a new handler each time the dropdown is opened, so forceLanguage() is called many times for each dropdown click after you've been using it for a while. Better to move this down into _init().

var selectedLang = LanguageManager.getLanguage($(this).val()),
defaultLang = LanguageManager.getLanguageForPath(
document.file.fullPath
);
// if default language selected, don't "force"" it
// (passing in null will reset the force flag)
document.forceLanguage(
selectedLang === defaultLang ? null : selectedLang
);
$languageSelect.css("width", "auto"); // unlock width
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs to happen whenever _updateLanguageInfo() runs, since the user might open the dropdown and then close it again without selecting anything -- which currently leaves the width "locked," resulting in truncation if you switch to a different file with a longer language name.

});
}

function _init() {
$languageInfo = $("#status-language");
$languageSelect = $("#language-select");
$cursorInfo = $("#status-cursor");
$fileInfo = $("#status-file");
$indentType = $("#indent-type");
Expand Down Expand Up @@ -180,7 +232,13 @@ define(function (require, exports, module) {
});

$indentWidthInput.focus(function () { $indentWidthInput.select(); });


// When language select clicked, set up dropdown.
// Using mousedown because the dropdown opens before mouseup.
$languageSelect.on("mousedown", function () {
_setupLanguageSelect(EditorManager.getActiveEditor().document);
});

_onActiveEditorChange(null, EditorManager.getActiveEditor(), null);
}

Expand Down
10 changes: 10 additions & 0 deletions src/language/LanguageManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,15 @@ define(function (require, exports, module) {
return language || _fallbackLanguage;
}

/**
* Returns all of the languages currently defined in the LanguageManager.
* @return {Object.<string, Language>} A map containing all of the
* languages currently defined.
*/
function getLanguages() {
return $.extend({}, _languages); // copy to prevent modification
}

/**
* Resolves a CodeMirror mode to a Language object.
* @param {!string} mode CodeMirror mode
Expand Down Expand Up @@ -754,4 +763,5 @@ define(function (require, exports, module) {
exports.defineLanguage = defineLanguage;
exports.getLanguage = getLanguage;
exports.getLanguageForPath = getLanguageForPath;
exports.getLanguages = getLanguages;
});
27 changes: 27 additions & 0 deletions src/styles/brackets.less
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,33 @@ a, img {
#status-language {
border-right: 1px solid rgba(0, 0, 0, 0.1);
}

/**
* Custom <select> styling currently only being used for language selection
* but could be reused elsewhere.
* (Here's a good intro to custom form fields: http://goo.gl/T4EPg)
*/
select.status-bar-select {
-webkit-appearance: none;
-webkit-font-smoothing: inherit;
background: url("images/select-triangles.svg") no-repeat right center;
border: 0;
// have to explicitly inherit some styles to override <select> defaults
color: inherit;
font-family: inherit;
font-size: inherit;
height: inherit;
line-height: inherit;
margin: 0;
padding: 0 12px 0 0;
width: auto;
&:focus {
outline: 0;
}
&:hover {
text-decoration: underline;
}
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dropdown appears weirdly off-center:
language picker

I'm not sure if this is an artifact of how the actual select is smaller than the area between the status bar dividers, or an unavoidable side effect of using custom styling, or what... it almost makes me wonder if we'd be better off with a custom dropdown like the ones we use for code hints, context menus, the Recent Projects dropdown, etc.

}

@-webkit-keyframes spinner-sprites-12 {
Expand Down
11 changes: 11 additions & 0 deletions src/styles/images/select-triangles.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/widgets/StatusBar.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
<div id="indent-width-label"></div>
<input id="indent-width-input" type="number" min="1" max="10" maxlength="2" size="2" class="hidden">
</div>
<div id="status-language"></div>
<div id="status-language">
<select id="language-select" class="status-bar-select"></select>
</div>
<div class="spinner"></div>
</div>
</div>