Browse Source

Merge pull request #1186 from AtomicGameEngine/TSH-ATOMIC-697

Shortcut fixes for #697
JoshEngebretson 9 years ago
parent
commit
8dc9c49924

+ 12 - 0
Data/AtomicEditor/CodeEditor/MonacoEditor.html

@@ -106,6 +106,18 @@
                 interop.getInstance().preferencesChanged(prefs);
             });
         }
+
+        function HOST_invokeShortcut(shortcut) {
+            setupEditor.then((interop) => {
+                interop.getInstance().invokeShortcut(shortcut);
+            });
+        }
+
+        function HOST_formatCode() {
+            setupEditor.then((interop) => {
+                interop.getInstance().formatCode();
+            });
+        }
     </script>
 
 </body>

+ 4 - 4
Script/AtomicEditor/ui/Shortcuts.ts

@@ -38,7 +38,7 @@ class Shortcuts extends Atomic.ScriptObject {
     }
 
     //this should be moved somewhere else...
-    invokePlayOrStopPlayer(debug:boolean = false) {
+    invokePlayOrStopPlayer(debug: boolean = false) {
         this.sendEvent(EditorEvents.SaveAllResources);
         if (Atomic.editorMode.isPlayerEnabled()) {
             this.sendEvent("IPCPlayerExitRequest");
@@ -63,8 +63,8 @@ class Shortcuts extends Atomic.ScriptObject {
 
                         let pos = Atomic.graphics.windowPosition;
 
-                        playerWindow.x = pos[0] + (Atomic.graphics.width/2 - playerWindow.width/2);
-                        playerWindow.y = pos[1] + (Atomic.graphics.height/2 - playerWindow.height/2);
+                        playerWindow.x = pos[0] + (Atomic.graphics.width / 2 - playerWindow.width / 2);
+                        playerWindow.y = pos[1] + (Atomic.graphics.height / 2 - playerWindow.height / 2);
 
                         // if too small a window, use default (which maximizes)
                         if (playerWindow.width < 480) {
@@ -164,7 +164,7 @@ class Shortcuts extends Atomic.ScriptObject {
         }
     }
 
-    invokeResourceFrameShortcut(shortcut: string) {
+    invokeResourceFrameShortcut(shortcut: Editor.EditorShortcutType) {
         if (!ToolCore.toolSystem.project) return;
         var resourceFrame = EditorUI.getMainFrame().resourceframe.currentResourceEditor;
         if (resourceFrame) {

+ 1 - 0
Script/AtomicWebViewEditor/clientExtensions/ClientExtensionEventNames.ts

@@ -30,4 +30,5 @@ export default class ClientExtensionEventNames {
     static ResourceRenamedEvent = "ResourceRenamedEvent";
     static ResourceDeletedEvent = "ResourceDeletedEvent";
     static PreferencesChangedEvent = "PreferencesChangedEvent";
+    static FormatCodeEvent = "FormatCodeEvent";
 }

+ 17 - 0
Script/AtomicWebViewEditor/clientExtensions/ClientExtensionServices.ts

@@ -101,6 +101,7 @@ export class WebViewServicesProvider extends ServicesProvider<Editor.ClientExten
         eventDispatcher.subscribeToEvent(ClientExtensionEventNames.ResourceDeletedEvent, (ev) => this.deleteResource(ev));
         eventDispatcher.subscribeToEvent(ClientExtensionEventNames.CodeSavedEvent, (ev) => this.saveCode(ev));
         eventDispatcher.subscribeToEvent(ClientExtensionEventNames.PreferencesChangedEvent, (ev) => this.preferencesChanged(ev));
+        eventDispatcher.subscribeToEvent(ClientExtensionEventNames.FormatCodeEvent, (ev) => this.formatCode());
     }
 
     /**
@@ -171,6 +172,22 @@ export class WebViewServicesProvider extends ServicesProvider<Editor.ClientExten
         });
     }
 
+    /**
+     * Called when the editor code should be formatted
+     */
+    formatCode() {
+        this.registeredServices.forEach((service) => {
+            try {
+                // Verify that the service contains the appropriate methods and that it can handle the rename
+                if (service.formatCode) {
+                    service.formatCode();
+                }
+            } catch (e) {
+                alert(`Error detected in extension ${service.name}\n \n ${e.stack}`);
+            }
+        });
+    }
+
     /**
      * Called when the editor is requesting to be configured for a particular file
      * @param  {Editor.EditorEvents.EditorFileEvent} ev

+ 15 - 8
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/javascript/JavascriptLanguageExtension.ts

@@ -27,6 +27,9 @@ export default class JavascriptLanguageExtension implements Editor.ClientExtensi
     name: string = "ClientJavascriptLanguageExtension";
     description: string = "Javascript language services for the editor.";
 
+    private editor: monaco.editor.IStandaloneCodeEditor;
+    private active = false;
+
     private serviceLocator: Editor.ClientExtensions.ClientServiceLocator;
 
     /**
@@ -55,14 +58,18 @@ export default class JavascriptLanguageExtension implements Editor.ClientExtensi
      */
     configureEditor(ev: Editor.EditorEvents.EditorFileEvent) {
         if (this.isValidFiletype(ev.filename)) {
-            // TODO: configure the editor
-            //let editor = <AceAjax.Editor>ev.editor;
-            //editor.session.setMode("ace/mode/javascript");
-
-            //editor.setOptions({
-                //enableBasicAutocompletion: true,
-                //enableLiveAutocompletion: true
-            //});
+            this.editor = ev.editor; // cache this so that we can reference it later
+            this.active = true;
+        } else {
+            this.active = false;
         }
     }
+
+    /**
+     * Format the code
+     * @memberOf JavascriptLanguageExtension
+     */
+    formatCode() {
+        // do nothing.  This is being handled by the TypeScriptLanguageExtension
+    }
 }

+ 11 - 1
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/turbobadger/TurboBadgerLanguageExtension.ts

@@ -28,6 +28,7 @@ export default class TurboBadgerLanguageExtension implements Editor.ClientExtens
     description: string = "TurboBadger language services for the editor.";
 
     private serviceLocator: Editor.ClientExtensions.ClientServiceLocator;
+    private active = false;
 
     /**
     * Initialize the language service
@@ -54,7 +55,7 @@ export default class TurboBadgerLanguageExtension implements Editor.ClientExtens
      */
     configureEditor(ev: Editor.EditorEvents.EditorFileEvent) {
         if (this.isValidFiletype(ev.filename)) {
-
+            this.active = true;
             monaco.languages.register({ id: "turbobadger" });
             // TODO: set up syntax hilighter
             // monaco.languages.setMonarchTokensProvider("turbobadger", this.getTokensProvider());
@@ -80,4 +81,13 @@ export default class TurboBadgerLanguageExtension implements Editor.ClientExtens
             });
         }
     }
+
+    /**
+     * Format the code
+     */
+    formatCode() {
+        if (this.active) {
+            alert("Code formatted not available for this syntax.");
+        }
+    }
 }

+ 29 - 2
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/TypescriptLanguageExtension.ts

@@ -131,6 +131,8 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
      */
     configureEditor(ev: Editor.EditorEvents.EditorFileEvent) {
         if (this.isValidFiletype(ev.filename)) {
+            let editor = ev.editor as monaco.editor.IStandaloneCodeEditor;
+            this.editor = editor; // cache this so that we can reference it later
             this.active = true;
 
             this.overrideBuiltinServiceProviders();
@@ -143,8 +145,6 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
 
             this.filename = ev.filename;
 
-            let editor = ev.editor as monaco.editor.IStandaloneCodeEditor;
-            this.editor = editor; // cache this so that we can reference it later
             // Let's turn some things off in the editor.  These will be provided by the shared web worker
             if (this.isJsFile(ev.filename)) {
                 monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
@@ -287,6 +287,33 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
         }
     }
 
+    /**
+     * Format the code
+     */
+    formatCode() {
+        if (this.active) {
+            const action = this.editor.getAction("editor.action.format");
+            if (action && action.isSupported()) {
+                let wasEmpty = false;
+                let cursorPosition;
+
+                if (this.editor.getSelection().isEmpty()) {
+                    wasEmpty = true;
+                    cursorPosition = this.editor.getPosition();
+
+                    this.editor.setSelection(this.editor.getModel().getFullModelRange());
+                }
+
+                action.run().then(() => {
+                    // Make sure we put the cursor back to where it was
+                    if (wasEmpty && cursorPosition) {
+                        this.editor.setPosition(cursorPosition);
+                    }
+                });
+            }
+        }
+    }
+
     /**
      * Request the markers to display
      */

+ 35 - 1
Script/AtomicWebViewEditor/editor/editorCommands.ts

@@ -33,7 +33,7 @@ import ClientExtensionEventNames from "../clientExtensions/ClientExtensionEventN
 export function configure(fileExt: string, filename: string) {
 
     // converter to handle new version of the renderWhitespace setting
-    const renderWhitespaceAdapter = (setting): 'none' | 'boundary' | 'all' => {
+    const renderWhitespaceAdapter = (setting): "none" | "boundary" | "all" => {
         switch (setting.toLowerCase()) {
             case "true": return "all";
             case "false": return "none";
@@ -56,6 +56,11 @@ export function configure(fileExt: string, filename: string) {
         filename: filename,
         editor: monacoEditor
     });
+
+    // Override CMD/CTRL+I since that is going to be used for Format Code and in the editor it is assigned to something else
+    const noOpCommand: monaco.editor.ICommandHandler = () => { };
+    monacoEditor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_I, noOpCommand, null);
+
 }
 
 /**
@@ -154,3 +159,32 @@ export function preferencesChanged(prefs: Editor.ClientExtensions.PreferencesCha
 export function setEditor(editor: any) {
     internalEditor.setInternalEditor(editor);
 }
+
+/**
+ * Called when a resource is getting deleted
+ * @param  {string} path
+ */
+export function formatCode() {
+    serviceLocator.sendEvent(ClientExtensionEventNames.FormatCodeEvent, null);
+}
+
+/**
+ * Called when the editor should respond to a host shortcut command
+ */
+export function invokeShortcut(shortcut: Editor.EditorShortcutType) {
+
+    const ed = internalEditor.getInternalEditor();
+    ed.focus();
+
+    switch (shortcut) {
+        case "cut":
+        case "copy":
+        case "paste":
+            window.document.execCommand(shortcut);
+            break;
+
+        case "selectall":
+            ed.setSelection(ed.getModel().getFullModelRange());
+            break;
+    }
+}

+ 15 - 0
Script/AtomicWebViewEditor/interop.ts

@@ -226,4 +226,19 @@ export default class HostInteropType {
     setEditor(editor: any) {
         editorCommands.setEditor(editor);
     }
+
+    /**
+     * Called when a shortcut should be invoked, coming from the host editor
+     * @param {Editor.EditorShortcutType} shortcut shortcut to be executed
+     */
+    invokeShortcut(shortcut: Editor.EditorShortcutType) {
+       editorCommands.invokeShortcut(shortcut);
+    }
+
+    /**
+     * Format the code inside the editor
+     */
+    formatCode() {
+        editorCommands.formatCode();
+    }
 }

+ 8 - 0
Script/TypeScript/EditorWork.d.ts

@@ -420,6 +420,7 @@ declare module Editor.ClientExtensions {
         delete?(ev: EditorEvents.DeleteResourceEvent);
         rename?(ev: EditorEvents.RenameResourceEvent);
         projectUnloaded?();
+        formatCode?();
         preferencesChanged?(preferences: PreferencesChangedEventData);
     }
 
@@ -514,3 +515,10 @@ declare module Editor.ClientExtensions {
         addCustomHostRoutine(routineName: string, callback: (...any) => void);
     }
 }
+
+declare module Editor {
+    /**
+     * Valid editor shortcuts that can be called from menus
+     */
+    export type EditorShortcutType = "cut" | "copy" | "paste" | "undo" | "redo" | "close" | "frameselected" | "selectall";
+}

+ 36 - 1
Source/AtomicEditor/Editors/JSResourceEditor.cpp

@@ -167,7 +167,7 @@ void JSResourceEditor::HandleWebMessage(StringHash eventType, VariantMap& eventD
 
 void JSResourceEditor::FormatCode()
 {
-    //webClient_->ExecuteJavaScript("beautifyCode();");
+    webClient_->ExecuteJavaScript("HOST_formatCode();");
 }
 
 bool JSResourceEditor::OnEvent(const TBWidgetEvent &ev)
@@ -177,6 +177,41 @@ bool JSResourceEditor::OnEvent(const TBWidgetEvent &ev)
         if (ev.ref_id == TBIDC("close"))
         {
             RequestClose();
+        } else if (ev.ref_id == TBIDC("undo")) {
+            // Need to physically send the CTRL/CMD+Z to the browser so that
+            // the internal editor responds appropriately.  The browser UNDO doesn't fire off
+            // the right events inside the editor.
+            VariantMap map;
+            map[KeyUp::P_KEY] = KEY_Z;
+            map[KeyUp::P_SCANCODE] = SCANCODE_Z;
+            #ifdef ATOMIC_PLATFORM_OSX
+            map["ForceSuperDown"] = true;
+            #else
+            map[KeyUp::P_QUALIFIERS] = QUAL_CTRL;
+            webClient_->SendFocusEvent();
+            #endif
+            webClient_->SendKeyEvent( StringHash("KeyDown"), map);
+        } else if (ev.ref_id == TBIDC("redo")) {
+            // Need to physically send the CTRL/CMD+SHIFT+Z to the browser so that
+            // the internal editor responds appropriately.  The browser REDO doesn't fire off
+            // the right events inside the editor.
+            VariantMap map;
+            map[KeyUp::P_KEY] = KEY_Z;
+            map[KeyUp::P_SCANCODE] = SCANCODE_Z;
+            #ifdef ATOMIC_PLATFORM_OSX
+            map[KeyUp::P_QUALIFIERS] = QUAL_SHIFT;
+            map["ForceSuperDown"] = true;
+            #else
+            map[KeyUp::P_QUALIFIERS] = QUAL_SHIFT | QUAL_CTRL;
+            webClient_->SendFocusEvent();
+            #endif
+            webClient_->SendKeyEvent( StringHash("KeyDown"), map);
+        } else {
+            String shortcut;
+            UI* ui = GetSubsystem<UI>();
+            ui->GetTBIDString(ev.ref_id, shortcut);
+
+            webClient_->ExecuteJavaScript(ToString("HOST_invokeShortcut(\"%s\");", shortcut.CString()));
         }
     }
 

+ 2 - 0
Source/AtomicWebView/WebClient.cpp

@@ -353,6 +353,8 @@ public:
         browserSettings.file_access_from_file_urls = STATE_ENABLED;
         browserSettings.universal_access_from_file_urls = STATE_ENABLED;
         browserSettings.web_security = WebBrowserHost::GetWebSecurity() ? STATE_ENABLED : STATE_DISABLED;
+        browserSettings.javascript_access_clipboard = STATE_ENABLED;
+        browserSettings.javascript_dom_paste = STATE_ENABLED;
 
         windowInfo.width = width;
         windowInfo.height = height;