Browse Source

[editor] Add placeholder a in the Ace Editor Vue component

Johan Ahlen 5 năm trước cách đây
mục cha
commit
2f925bcb8d

+ 2 - 1
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/AceAnchoredRange.ts

@@ -14,8 +14,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import { Disposable } from 'components/utils/SubscriptionTracker';
+import ace from 'ext/aceHelper';
 import { Ace } from 'ext/ace';
+import { Disposable } from 'components/utils/SubscriptionTracker';
 import { ParsedLocation } from 'parse/types';
 
 const clearGutterCss = (

+ 35 - 2
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/AceEditor.vue

@@ -18,7 +18,7 @@
 
 <template>
   <div class="ace-editor-component">
-    <div :id="id" class="ace-editor" />
+    <div :id="id" ref="editorElement" class="ace-editor" />
     <ace-autocomplete v-if="editor" :editor="editor" :editor-id="id" :executor="executor" />
   </div>
 </template>
@@ -76,7 +76,7 @@
     }
 
     mounted(): void {
-      const editorElement = this.$el.querySelector('.ace-editor');
+      const editorElement = <HTMLElement>this.$refs['editorElement'];
       if (!editorElement) {
         return;
       }
@@ -239,15 +239,39 @@
         }
       };
 
+      const onPaste = (e: { text: string }): void => {
+        e.text = removeUnicodes(e.text);
+      };
+
+      let placeholderVisible = false;
+      const placeholderElement = this.createPlaceholderElement();
+      const onInput = () => {
+        if (!placeholderVisible) {
+          if (!editor.getValue().length) {
+            editor.renderer.scroller.append(placeholderElement);
+            placeholderVisible = true;
+          }
+        } else {
+          placeholderElement.remove();
+          placeholderVisible = false;
+        }
+      };
+
+      onInput();
+
       editor.on('change', triggerChange);
       editor.on('blur', triggerChange);
       editor.on('focus', onFocus);
+      editor.on('paste', onPaste);
+      editor.on('input', onInput);
 
       this.subTracker.addDisposable({
         dispose: () => {
           editor.off('change', triggerChange);
           editor.off('blur', triggerChange);
           editor.off('focus', onFocus);
+          editor.off('paster', onPaste);
+          editor.off('input', onInput);
         }
       });
 
@@ -273,6 +297,15 @@
       this.$emit('ace-created', editor);
     }
 
+    createPlaceholderElement(): HTMLElement {
+      const element = document.createElement('div');
+      element.innerText = I18n('Example: SELECT * FROM tablename, or press CTRL + space');
+      element.style.marginLeft = '6px';
+      element.classList.add('ace_invisible');
+      element.classList.add('ace_emptyMessage');
+      return element;
+    }
+
     cursorAtStartOfStatement(): boolean {
       return (
         !!this.editor &&

+ 4 - 0
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/__snapshots__/AceEditor.test.ts.snap

@@ -62,6 +62,10 @@ exports[`AceEditor.vue should render 1`] = `
           />
         </div>
       </div>
+      <div
+        class="ace_invisible ace_emptyMessage"
+        style="margin-left: 6px;"
+      />
     </div>
     <div
       class="ace_scrollbar ace_scrollbar-v"

+ 1 - 1
desktop/core/src/desktop/js/apps/notebook2/components/aceEditor/autocomplete/AceAutocomplete.vue

@@ -233,7 +233,7 @@
                 console.log(parseResult);
               }
 
-              if (parseResult) {
+              if (parseResult && this.autocompleteResults) {
                 this.suggestions = [];
                 this.autocompleteResults.update(parseResult, this.suggestions).finally(() => {
                   this.loading = false;

+ 3 - 0
desktop/core/src/desktop/js/ext/ace.d.ts

@@ -50,12 +50,15 @@ declare namespace Ace {
       removeKeyboardHandler(hashHandler: HashHandler): void;
     }
     lastChangeTime: number;
+    moveCursorTo(row: number, col: number): void;
     moveCursorToPosition(position: Position): void;
     off(ev: string, callback: ((e: any) => any) | number): void;
     on(event: string, fn: (e: any) => any): number;
     removeTextAfterCursor(length: number): void;
+    removeTextBeforeCursor(length: number): void;
     renderer: {
       scrollLeft: number;
+      scroller: HTMLElement;
       gutterWidth: number;
       lineHeight: number;
       layerConfig: {

+ 18 - 1
desktop/core/src/desktop/js/ext/aceHelper.ts

@@ -1,3 +1,19 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// 'License'); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an 'AS IS' BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 import 'ext/ace/ace'
 import 'ext/ace/ext-language_tools';
 import 'ext/ace/ext-searchbox';
@@ -52,4 +68,5 @@ const DIALECT_ACE_MODE_MAPPING: { [dialect: string]: string } = {
   'sql': 'ace/mode/sql'
 };
 
-export const getAceMode = (dialect?: string): string => (dialect && DIALECT_ACE_MODE_MAPPING[dialect]) || DIALECT_ACE_MODE_MAPPING.sql
+export const getAceMode = (dialect?: string): string =>
+  (dialect && DIALECT_ACE_MODE_MAPPING[dialect]) || DIALECT_ACE_MODE_MAPPING.sql;