diff --git a/ide/static/ide/css/ide.css b/ide/static/ide/css/ide.css index c5017e42..ce5638fe 100644 --- a/ide/static/ide/css/ide.css +++ b/ide/static/ide/css/ide.css @@ -1136,8 +1136,25 @@ span.cm-autofilled-end { text-align: left; } -#fuzzy-results > div { +.fuzzy-subheader { + font-weight: bold; + color: #666; + font-variant: small-caps; + margin-left: 1em; +} + +.fuzzy-hint { + opacity: 0.5; +} +.fuzzy-hint::before { + content: ' <'; +} +.fuzzy-hint::after { + content: '>'; +} + +#fuzzy-results > div { line-height: 28px; cursor: pointer; cursor: hand; diff --git a/ide/static/ide/js/cloudpebble.js b/ide/static/ide/js/cloudpebble.js index 306c0633..cc179401 100644 --- a/ide/static/ide/js/cloudpebble.js +++ b/ide/static/ide/js/cloudpebble.js @@ -15,6 +15,10 @@ CloudPebble.ProgressBar = (function() { }, Hide: function() { hide(); + }, + Error: function(msg) { + $('#progress-pane').find('.progress').addClass('progress-danger').removeClass('progress-striped') + .after($('
').text(msg).css({margin: 'auto', width: '300px'})); } }; })(); @@ -67,7 +71,6 @@ CloudPebble.Init = function() { CloudPebble.Dependencies.Init(); CloudPebble.Documentation.Init(); CloudPebble.FuzzyPrompt.Init(); - CloudPebble.ProgressBar.Hide(); // Add source files. $.each(data.source_files, function(index, value) { @@ -86,8 +89,11 @@ CloudPebble.Init = function() { $('.sdk3-only').hide(); } return null; + }).then(function() { + CloudPebble.ProgressBar.Hide(); }).catch(function(err) { - alert("Something went wrong:\n" + err.message); + CloudPebble.ProgressBar.Error(err); + throw err; }); window.addEventListener('beforeunload', function(e) { @@ -233,46 +239,3 @@ CloudPebble.Utils = { return interpolate(ngettext("%s second", "%s seconds", n), [n]); } }; - -CloudPebble.GlobalShortcuts = (function() { - var make_shortcut_checker = function (command) { - if (!(command.indexOf('-') > -1)) { - command = _.findKey(CodeMirror.keyMap.default, _.partial(_.isEqual, command)); - } - var split = command.split('-'); - var modifier = ({ - 'ctrl': 'ctrlKey', - 'cmd': 'metaKey' - })[split[0].toLowerCase()]; - return function (e) { - return (e[modifier] && String.fromCharCode(e.keyCode) == split[1]); - } - }; - - - var global_shortcuts = {}; - - $(document).keydown(function (e) { - if (!e.isDefaultPrevented()) { - _.each(global_shortcuts, function (shortcut) { - if (shortcut.checker(e)) { - shortcut.func(e); - e.preventDefault(); - } - }); - } - }); - - return { - SetShortcutHandlers: function (shortcuts) { - var new_shortcuts = _.mapObject(shortcuts, function (func, key) { - return { - checker: make_shortcut_checker(key), - func: func - }; - - }); - _.extend(global_shortcuts, new_shortcuts); - } - } -})(); diff --git a/ide/static/ide/js/compile.js b/ide/static/ide/js/compile.js index 26ab6846..f51b422c 100644 --- a/ide/static/ide/js/compile.js +++ b/ide/static/ide/js/compile.js @@ -179,10 +179,9 @@ CloudPebble.Compile = (function() { commands[gettext("Show Phone Logs")] = function() { show_app_logs(ConnectionType.Phone); }; commands[gettext("Show Emulator Logs")] = function() { show_app_logs(ConnectionType.Qemu); }; commands[gettext("Show Last Build Log")] = function() {show_build_log(mLastBuild.id)}; - commands[gettext("Compilation")] = function() { show_compile_pane();}; commands[gettext("Clear App Logs")] = function() { show_clear_logs_prompt(); }; commands[gettext("Take Screenshot")] = function() { take_screenshot(); }; - CloudPebble.FuzzyPrompt.AddCommands(commands); + CloudPebble.FuzzyPrompt.AddCommands(gettext('Actions'), commands); SharedPebble.on('app_log', handle_app_log); SharedPebble.on('phone_log', handle_phone_log); diff --git a/ide/static/ide/js/dependencies.js b/ide/static/ide/js/dependencies.js index b2c48c8c..7e0ed808 100644 --- a/ide/static/ide/js/dependencies.js +++ b/ide/static/ide/js/dependencies.js @@ -609,9 +609,6 @@ CloudPebble.Dependencies = (function() { show_dependencies_pane(); }, Init: function() { - var commands = {}; - commands[gettext("Dependencies")] = CloudPebble.Dependencies.Show; - CloudPebble.FuzzyPrompt.AddCommands(commands); dependencies_template = $('#dependencies-pane-template').remove().removeClass('hide'); alerts.init(dependencies_template); diff --git a/ide/static/ide/js/editor.js b/ide/static/ide/js/editor.js index ac4498a5..9e83c7f2 100644 --- a/ide/static/ide/js/editor.js +++ b/ide/static/ide/js/editor.js @@ -4,6 +4,7 @@ CloudPebble.Editor = (function() { var unsaved_files = 0; var is_fullscreen = false; var resume_fullscreen = false; + var current_editor = null; var add_source_file = function(file) { CloudPebble.Sidebar.AddSourceFile(file, function() { @@ -129,8 +130,9 @@ CloudPebble.Editor = (function() { if(language_has_autocomplete && USER_SETTINGS.autocomplete === 2) { settings.extraKeys = {'Ctrl-Space': 'autocomplete'}; } + if(language_has_autocomplete && USER_SETTINGS.autocomplete !== 0) { - settings.extraKeys['Tab'] = function() { + settings.extraKeys['Tab'] = function selectNextArgument() { var marks = code_mirror.getAllMarks(); var cursor = code_mirror.getCursor(); var closest = null; @@ -163,7 +165,7 @@ CloudPebble.Editor = (function() { if(USER_SETTINGS.use_spaces) { var spaces = Array(settings.indentUnit + 1).join(' '); var oldTab = settings.extraKeys['Tab']; - settings.extraKeys['Tab'] = function(cm) { + settings.extraKeys['Tab'] = function indentMoreOrSelectNextArgument(cm) { // If we already overrode tab, check that one. if(oldTab) { if(oldTab(cm) !== CodeMirror.Pass) { @@ -213,12 +215,8 @@ CloudPebble.Editor = (function() { return CodeMirror.Pass; }; } - settings.extraKeys['Cmd-/'] = function(cm) { - CodeMirror.commands.toggleComment(cm); - }; - settings.extraKeys['Ctrl-/'] = function(cm) { - CodeMirror.commands.toggleComment(cm); - }; + settings.extraKeys['Ctrl-/'] = 'toggleComment'; + settings.extraKeys['Cmd-/'] = 'toggleComment'; settings.gutters = ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']; if(file_kind_in(['js', 'json'])) { @@ -262,10 +260,9 @@ CloudPebble.Editor = (function() { var help_shortcut = /Mac/.test(navigator.platform) ? 'Shift-Cmd-Ctrl-/' : 'Shift-Ctrl-Alt-/'; - settings.extraKeys[help_shortcut] = function(cm) { + settings.extraKeys[help_shortcut] = function lookupFunction(cm) { var pos = cm.cursorCoords(); var token = code_mirror.getTokenAt(cm.getCursor()); - create_popover(cm, token.string, pos.left, pos.top); }; @@ -484,13 +481,22 @@ CloudPebble.Editor = (function() { alert(gettext(interpolate("Failed to reload file. %s", [error]))); }); }; + + function set_save_shortcut() { + CloudPebble.GlobalShortcuts.SetShortcutHandlers({ + "PlatformCmd-S": save + }); + } + set_save_shortcut(); CloudPebble.Sidebar.SetActivePane(pane, { id: 'source-' + file.id, onRestore: function() { + current_editor = code_mirror; code_mirror.refresh(); _.defer(function() { code_mirror.focus(); }); check_safe(); + set_save_shortcut(); refresh_ib(); }, onSuspend: function() { @@ -498,6 +504,7 @@ CloudPebble.Editor = (function() { fullscreen(code_mirror, false); resume_fullscreen = true; } + current_editor = null; }, onDestroy: function() { if(!was_clean) { @@ -522,7 +529,7 @@ CloudPebble.Editor = (function() { CloudPebble.Sidebar.ClearIcon('source-' + file.id); }; - var save = function() { + function save() { // Make sure we're up to date with whatever changed in IB. if(ib_showing) { var content = code_mirror.getValue(); @@ -580,16 +587,12 @@ CloudPebble.Editor = (function() { }, pattern) }; + code_mirror.show_rename_prompt = show_rename_prompt; var ib_pane = $('#ui-editor-pane-template').clone().removeClass('hide').appendTo(pane).hide(); var ib_editor = new IB(ib_pane.find('.ui-canvas'), ib_pane.find('#ui-properties'), ib_pane.find('#ui-toolkit'), ib_pane.find('#ui-layer-list > div')); var ib_showing = false; - CloudPebble.GlobalShortcuts.SetShortcutHandlers({ - save: function() { - save().catch(alert); - } - }); function toggle_ib() { if(!ib_showing) { @@ -765,13 +768,6 @@ CloudPebble.Editor = (function() { fullscreen(code_mirror, true); } - var commands = {}; - commands[gettext('Rename File')] = function() { - // We need to use a timeout because the rename prompt will conflict with the old prompt - setTimeout(show_rename_prompt, 0); - }; - CloudPebble.FuzzyPrompt.ReplaceCommands(commands); - // Tell Google ga('send', 'event', 'file', 'open'); return code_mirror; @@ -779,6 +775,7 @@ CloudPebble.Editor = (function() { var error_box = $('
'); error_box.text(interpolate(gettext("Something went wrong: %s"), [error.message])); CloudPebble.Sidebar.SetActivePane(error_box, {id: ''}); + throw error; }).finally(function() { CloudPebble.ProgressBar.Hide(); }); @@ -796,7 +793,7 @@ CloudPebble.Editor = (function() { cm.showHint({hint: CloudPebble.Editor.Autocomplete.complete, completeSingle: false}); }; CodeMirror.commands.save = function(cm) { - cm.cloudpebble_save().catch(alert);; + cm.cloudpebble_save().catch(alert); }; CodeMirror.commands.saveAll = function(cm) { save_all().catch(alert); @@ -823,14 +820,50 @@ CloudPebble.Editor = (function() { edit_source_file(item.file); } }); - var commands = {}; + var global_commands = {}; if (CloudPebble.ProjectProperties.is_runnable) { - commands[gettext('Run')] = run; + global_commands[gettext('Run')] = run; } else { - commands[gettext('Build')] = run; + global_commands[gettext('Build')] = run; } + var local_commands = {}; + local_commands[gettext('Rename Source File')] = function() { + // We need to defer because the rename prompt will conflict with the old prompt + _.defer(function() { + current_editor.show_rename_prompt(); + }); + }; + + function neaten_command_name(str) { + var result = str.replace(/(\S)([A-Z])/g, '$1 $2').replace(/^./, function(str){ return str.toUpperCase(); }); + result = result.replace('Doc ', 'Document '); + result = result.replace('Go ', 'Go To '); + result = result.replace('Del ', 'Delete '); + return result; + } + + var codemirror_commands = [ + {command: 'indentAuto', refocus: true}, + {command: 'toggleComment', hint: 'Cmd-/ or Ctrl-/', refocus: true}, + 'find', 'replace', 'indentMore', 'indentLess', 'save', 'saveAll' + ]; + + _.each(codemirror_commands, function(entry) { + var command = !!entry.command ? entry.command : entry; + var name = (!!entry.name ? entry.name : neaten_command_name(command)); + local_commands[name] = function() { + current_editor.execCommand(command); + if (!!entry.refocus) current_editor.focus(); + }; + local_commands[name].hint = !!entry.hint ? entry.hint : CloudPebble.GlobalShortcuts.GetShortcutForCommand(command); + }); + + CloudPebble.FuzzyPrompt.AddCommands(gettext('File'), local_commands, function() { + return (!!current_editor); + }); + - CloudPebble.FuzzyPrompt.AddCommands(commands); + CloudPebble.FuzzyPrompt.AddCommands(gettext('Actions'), global_commands); } diff --git a/ide/static/ide/js/fuzzyprompt.js b/ide/static/ide/js/fuzzyprompt.js index 6b2cf063..8b3cea06 100644 --- a/ide/static/ide/js/fuzzyprompt.js +++ b/ide/static/ide/js/fuzzyprompt.js @@ -23,9 +23,8 @@ CloudPebble.FuzzyPrompt = (function() { this.name = opts.name; this.callback = opts.callback; this.object = opts.object; - this.id = opts.id; this.menu_item = opts.menu_item; - this.rank = opts.rank + this.subsection = opts.subsection; }; var init = function() { @@ -33,12 +32,20 @@ CloudPebble.FuzzyPrompt = (function() { // Set up the fuzzy matcher var options = { caseSensitive: false, - includeScore: false, + sortFn: function(a, b) { + return (a.score === b.score) ? a.item.name.localeCompare(b.item.name) : a.score - b.score; + }, shouldSort: true, - threshold: 0.4, + threshold: 0.5, location: 0, - distance: 20, - keys: ["name"] + distance: 40, + keys: [{ + name: 'name', + weight: 0.8 + }, { + name: 'subsection', + weight: 0.2 + }] }; fuse = new Fuse([], options); @@ -49,21 +56,24 @@ CloudPebble.FuzzyPrompt = (function() { var modifier = /Mac/.test(navigator.platform) ? 'metaKey' : 'ctrlKey'; // Register ctrl-p and ctrl-shift-p - $(document).keydown(function(e) { - if ((e[modifier]) && e.keyCode == 80) { - e.preventDefault(); - if (e.shiftKey) { - input.attr('placeholder', gettext("Enter Command")); - show_prompt('commands'); - } - else if (!e.shiftKey) { + CloudPebble.GlobalShortcuts.SetShortcutHandlers({ + 'PlatformCmd-P': { + func: function() { input.attr('placeholder', gettext("Search Files")); show_prompt('files'); - } + }, + name: gettext("Find File") + }, + 'Shift-PlatformCmd-P': { + func: function() { + input.attr('placeholder', gettext("Enter Command")); + show_prompt('commands'); + }, + name: gettext("Find Action") } }); - prompt.keydown(function (e) { + prompt.keydown(function(e) { // Ctrl-P to hide if (opened && e[modifier] && e.keyCode == 80) { hide_prompt(true); @@ -103,11 +113,7 @@ CloudPebble.FuzzyPrompt = (function() { // Then build the new results list if (matches.length > 0) { - _.each(matches, function(match, rank) { - match.menu_item.appendTo(results); - // The item's rank is its current position in the suggestion list. - match.rank = rank; - }); + render_list(matches); // Highlight the first item if the previously highlighted item disappears // or the user has not been using the arrow keys if (!manual || !(_.chain(matches).pluck('id')).contains(selected_id).value()) { @@ -121,7 +127,7 @@ CloudPebble.FuzzyPrompt = (function() { } }); - prompt.on('shown.bs.modal', function () { + prompt.on('shown.bs.modal', function() { input.focus(); input.val(""); }); @@ -148,7 +154,7 @@ CloudPebble.FuzzyPrompt = (function() { var parts = input.val().split(":", 2); if (parts[0].length == 0) { if (_.isUndefined(parts[1])) - return item_list; + return item_list;//_.sortBy(item_list, 'name'); else { return _.where(item_list, {name: default_item}); } @@ -185,39 +191,90 @@ CloudPebble.FuzzyPrompt = (function() { opened = true; prompt_kind = kind; // Build up the list of files to search through - var id = 0; _.each(sources, function(source) { if (source.kind == kind) { - _.each(source.list_func(), function (object, name) { - name = (!_.isFunction(object) && object.name ? object.name : name); - var menu_item = $("
"); - menu_item.text(name).appendTo(results); - // Set up the menu item handler - (function () { - var this_id = id; - menu_item.on('click', function () { - select_item(item_list[this_id]); - }); - })(); + if ((_.isFunction(source.should_show) && source.should_show()) || source.should_show === true) { + _.each(source.list_func(), function(object, name) { + name = (!_.isFunction(object) && object.name ? object.name : name); + var menu_item = $("
").append('').text(name); + if (object.hint) { + menu_item.append($('').addClass('fuzzy-hint').text(object.hint)); + } - item_list.push(new Item({ - name: name, - callback: source.callback, - object: object, - id: id, - menu_item: menu_item, - rank: id - })); - id++; - }); + item_list.push(new Item({ + name: name, + callback: source.callback, + object: object, + menu_item: menu_item, + subsection: source.subsection + })); + id++; + }); + } } }); + item_list = _.sortBy(item_list, 'name'); + var id = 0; + _.each(item_list, function(item) { + // Set up the menu item handler + (function() { + var this_id = id; + item.id = id; + item.rank = id; + item.menu_item.on('click', function() { + select_item(item_list[this_id]); + }); + id += 1; + })(); + }); + fuse.set(item_list); + item_list = _.sortBy(item_list, 'name'); + render_list(item_list); // Select the current item by default, or the first item. highlight_item(_.findWhere(item_list, {name: default_item}) || item_list[0]); }; + function render_list(item_list) { + var grouped = _.groupBy(item_list, 'subsection'); + var sections = _.keys(grouped); + function add_items(current_rank, items) { + _.each(items, function(item) { + item.rank = current_rank; + results.append(item.menu_item); + current_rank +=1; + }); + return current_rank; + } + + if (sections.length === 1) { + if (sections[0] != 'undefined') { + results.append($('
').text(sections[0]).addClass('fuzzy-subheader')); + } + add_items(0, item_list); + // results.append(_.pluck(item_list, 'menu_item')); + } + else { + var found = {}; + var ordered = []; + var i = 0; + _.some(item_list, function(item) { + if (!_.has(found, item.subsection)) { + found[item.subsection] = true; + ordered.push(item.subsection); + i += 1; + } + if (i == sections.length) return true; + }); + var rank = 0; + _.each(ordered, function(name) { + results.append($('
').text(name).addClass('fuzzy-subheader')); + rank = add_items(rank, grouped[name]); + }); + } + } + /** Highlight an item in the suggestions list. If enter is hit, the highlighted item gets selected. * * @param {Item} item An item object. @@ -254,7 +311,7 @@ CloudPebble.FuzzyPrompt = (function() { opened = false; prompt.modal('hide'); if (refocus) { - setTimeout(function () { + setTimeout(function() { $(previously_active).focus(); }, 1); } @@ -265,14 +322,6 @@ CloudPebble.FuzzyPrompt = (function() { } }; - var add_commands = function(commands) { - sources.push({ - list_func: function() {return commands;}, - callback: function(func) {func();}, - kind: 'commands' - }); - }; - return { /** Let fuzzy-prompt know the name of the currently open file/location to use as a default * when nothing has been typed. @@ -293,46 +342,36 @@ CloudPebble.FuzzyPrompt = (function() { * @param {string} kind 'files' or 'commands' * @param {Function} item_getter A function which should return a dict of items with string name keys * @param {Function} select_callback A function to call when one of these items is selected + * @param {Function|Boolean} should_show Whether to actually show the commands. Either true, or a function which returns a boolean. */ - AddDataSource: function(kind, item_getter, select_callback) { - sources.push({list_func: item_getter, callback: select_callback, kind: kind}); + AddDataSource: function(kind, item_getter, select_callback, should_show) { + if (_.isUndefined(should_show)) should_show = true; + sources.push({ + list_func: item_getter, + callback: select_callback, + kind: kind, + should_show: should_show + }); }, /** Add a set of commands * * @param {Object.} commands A dictionary of names->functions + * @param {Function|Boolean} should_show Whether to actually show the commands. */ - AddCommands: function(commands) { - add_commands(commands); - }, - /** Add a new set of commands, replacing any identically named commands - * - * @param {Object.} commands A dictionary of names->functions - */ - ReplaceCommands: function(commands) { - // For each new command, look through the data source for - // commands with the same name. If we find any, replace their functions - // with the new one. - var all_replaced = []; - - _.each(commands, function(newfunc, compare_key) { - _.each(sources, function (source) { - if (source.kind == 'commands') { - var source_commands = source.list_func(); - _.each(source_commands, function (func, key) { - if (compare_key == key) { - source_commands[key] = newfunc; - // Keep track of the fact that this command was replaced - all_replaced.push(key); - } - }); - source.list_func = function() {return source_commands}; - } - }); + AddCommands: function(subsection, commands, should_show) { + if (_.isUndefined(should_show)) should_show = true; + sources.push({ + list_func: function() { + return commands; + }, + callback: function(func) { + func(); + }, + kind: 'commands', + should_show: should_show, + subsection: subsection }); - - // At the end, we add any commands in the set which were new and note replacements. - var filtered = _.omit(commands, all_replaced); - add_commands(filtered); + // CloudPebble.FuzzyPrompt.AddDataSource('commands', , , should_show); }, Init: function() { init(); diff --git a/ide/static/ide/js/global_shortcuts.js b/ide/static/ide/js/global_shortcuts.js new file mode 100644 index 00000000..dccf6163 --- /dev/null +++ b/ide/static/ide/js/global_shortcuts.js @@ -0,0 +1,75 @@ +CloudPebble.GlobalShortcuts = (function () { + var global_shortcuts = {}; + + // Build a full map of CodeMirror shortcuts by checking for the 'fallthrough' property + // and integrating any sub-keymaps of the main one. + var codemirror_full_keymap = _.clone(CodeMirror.keyMap[USER_SETTINGS.keybinds]); + if (codemirror_full_keymap.fallthrough) { + _.each(codemirror_full_keymap.fallthrough, function(sub_map) { + _.defaults(codemirror_full_keymap, CodeMirror.keyMap[sub_map]); + }); + delete codemirror_full_keymap.fallthrough; + } + + $(document).keydown(function (e) { + if (!e.isDefaultPrevented()) { + var shortcut = global_shortcuts[CodeMirror.keyName(e)]; + if (shortcut) { + e.preventDefault(); + shortcut.func(e); + } + } + }); + + function shortcut_for_command(command, commands) { + var look_through = _.isObject(commands) ? commands : codemirror_full_keymap; + // If the command is a name like "save", get they key-combo from CodeMirror + if (!(command.indexOf('-') > -1)) { + command = _.findKey(look_through, _.partial(_.isEqual, command)); + } + + // If any of the shortcut items are "platformcmd", convert them to 'Ctrl' or 'Cmd' depending on the platform. + function key_for_platform(name) { + if (name.toLowerCase() == "platformcmd") { + return /Mac/.test(navigator.platform) ? 'Cmd' : 'Ctrl' + } else return name; + } + + if (!command) { + return null; + } + return command.split('-').map(key_for_platform).join('-'); + } + + return { + /** Add or replace global shortcuts + * + * @param {Object} shortcuts The keys of this object must be strings which represent keyboard shortcuts. + * They can Codemirror-compatible shortcut descriptors e.g. "Shift-Cmd-V", or they can reference CodeMirror + * commands such as "Save". + * The values should be objects which have a descriptive "name" property, and also either have a "func" property + * or be functions themselves. For example, a named function fully satisfies the requirements, as does an object + * such as {name: "My Function", func: my_anonymous_function} + */ + SetShortcutHandlers: function (shortcuts) { + _.each(shortcuts, function (descriptor, key) { + var shortcut = shortcut_for_command(key); + if (shortcut) { + global_shortcuts[shortcut] = { + name: descriptor.name ? descriptor.name : key, + func: _.isFunction(descriptor) ? descriptor : descriptor.func + }; + } + }); + }, + GetShortcuts: function() { + return global_shortcuts; + }, + GetCodemirrorShortcuts: function() { + return codemirror_full_keymap; + }, + GetShortcutForCommand: function(name, extras) { + return shortcut_for_command(name, extras); + } + } +})(); diff --git a/ide/static/ide/js/resources.js b/ide/static/ide/js/resources.js index 21263df1..d130dfc7 100644 --- a/ide/static/ide/js/resources.js +++ b/ide/static/ide/js/resources.js @@ -470,15 +470,28 @@ CloudPebble.Resources = (function() { if(list_entry) { list_entry.addClass('active'); } - + function set_save_shortcut() { + CloudPebble.GlobalShortcuts.SetShortcutHandlers({ + "PlatformCmd-S": save + }); + } + set_save_shortcut(); CloudPebble.Sidebar.SetActivePane(pane, { id: 'resource-' + resource.id, - onRestore: _.partial(restore_pane, pane) + onRestore: function() { + restore_pane(pane); + set_save_shortcut(); + }, + onSuspend: function() { + CloudPebble.GlobalShortcuts.SetShortcutHandlers({ + "PlatformCmd-S": function() {return false;} + }); + } }); pane.find('#edit-resource-type').val(resource.kind).attr('disabled', 'disabled'); pane.find('#edit-resource-type').change(); - var save = function(e) { + function save(e) { if (e) e.preventDefault(); process_resource_form(form, false, resource.file_name, "/ide/project/" + PROJECT_ID + "/resource/" + resource.id + "/update").then(function(data) { delete project_resources[resource.file_name]; @@ -764,9 +777,6 @@ CloudPebble.Resources = (function() { }).init(); form.submit(save); - CloudPebble.GlobalShortcuts.SetShortcutHandlers({ - save: save - }); restore_pane(pane); }).finally(function() { diff --git a/ide/static/ide/js/settings.js b/ide/static/ide/js/settings.js index 42b9e15f..6fc4d892 100644 --- a/ide/static/ide/js/settings.js +++ b/ide/static/ide/js/settings.js @@ -409,7 +409,8 @@ CloudPebble.Settings = (function() { commands["GitHub"] = CloudPebble.GitHub.Show; commands[gettext("Timeline")] = CloudPebble.Timeline.show; commands[gettext("Add New Source File")] = CloudPebble.Editor.Create; - CloudPebble.FuzzyPrompt.AddCommands(commands); + commands[gettext("Dependencies")] = CloudPebble.Dependencies.Show; + CloudPebble.FuzzyPrompt.AddCommands(gettext('Navigation'), commands); settings_template = $('#settings-pane-template').remove().removeClass('hide'); }, AddResource: function(resource) { diff --git a/ide/templates/ide/project.html b/ide/templates/ide/project.html index 91e52f57..b6f1c6b9 100644 --- a/ide/templates/ide/project.html +++ b/ide/templates/ide/project.html @@ -575,6 +575,7 @@

{% trans 'Compass and Accelerometer' %}

+