|
@@ -5,16 +5,11 @@ import * as CodeMirror
|
|
|
from 'codemirror';
|
|
|
|
|
|
import 'codemirror/mode/meta';
|
|
|
-import 'codemirror/addon/runmode/runmode';
|
|
|
|
|
|
import {
|
|
|
Message
|
|
|
} from 'phosphor/lib/core/messaging';
|
|
|
|
|
|
-import {
|
|
|
- PanelLayout
|
|
|
-} from 'phosphor/lib/ui/panel';
|
|
|
-
|
|
|
import {
|
|
|
ResizeMessage, Widget
|
|
|
} from 'phosphor/lib/ui/widget';
|
|
@@ -25,16 +20,6 @@ import {
|
|
|
*/
|
|
|
const EDITOR_CLASS = 'jp-CodeMirrorWidget';
|
|
|
|
|
|
-/**
|
|
|
- * The class name added to a live codemirror widget.
|
|
|
- */
|
|
|
-const LIVE_CLASS = 'jp-CodeMirrorWidget-live';
|
|
|
-
|
|
|
-/**
|
|
|
- * The class name added to a static codemirror widget.
|
|
|
- */
|
|
|
-const STATIC_CLASS = 'jp-CodeMirrorWidget-static';
|
|
|
-
|
|
|
/**
|
|
|
* The name of the default CodeMirror theme
|
|
|
*/
|
|
@@ -54,38 +39,28 @@ class CodeMirrorWidget extends Widget {
|
|
|
constructor(options: CodeMirror.EditorConfiguration = {}) {
|
|
|
super();
|
|
|
this.addClass(EDITOR_CLASS);
|
|
|
- let layout = this.layout = new PanelLayout();
|
|
|
- this.node.tabIndex = -1;
|
|
|
options.theme = (options.theme || DEFAULT_CODEMIRROR_THEME);
|
|
|
- this._live = new LiveCodeMirror(options);
|
|
|
- this._static = new StaticCodeMirror(this._live.editor);
|
|
|
- layout.addWidget(this._static);
|
|
|
- layout.addWidget(this._live);
|
|
|
- this._live.hide();
|
|
|
+ this._editor = CodeMirror(this.node, options);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Dispose of the resources held by the widget.
|
|
|
*/
|
|
|
dispose(): void {
|
|
|
- this._static.dispose();
|
|
|
- this._live.dispose();
|
|
|
+ clearTimeout(this._resizing);
|
|
|
+ this._editor = null;
|
|
|
super.dispose();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Get the editor wrapped by the widget.
|
|
|
+ *
|
|
|
+ * #### Notes
|
|
|
+ * This is a ready-only property.
|
|
|
*/
|
|
|
- get editor(): CodeMirror.Editor {
|
|
|
- return this._live.editor;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Handle `'activate-request'` messages.
|
|
|
- */
|
|
|
- protected onActivateRequest(msg: Message): void {
|
|
|
- this._activate();
|
|
|
- }
|
|
|
+ get editor(): CodeMirror.Editor {
|
|
|
+ return this._editor;
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Handle the DOM events for the widget.
|
|
@@ -99,15 +74,9 @@ class CodeMirrorWidget extends Widget {
|
|
|
*/
|
|
|
handleEvent(event: Event): void {
|
|
|
switch (event.type) {
|
|
|
- case 'mousedown':
|
|
|
- this._evtMouseDown(event as MouseEvent);
|
|
|
- break;
|
|
|
case 'focus':
|
|
|
this._evtFocus(event as FocusEvent);
|
|
|
break;
|
|
|
- case 'blur':
|
|
|
- this._evtBlur(event as FocusEvent);
|
|
|
- break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -117,108 +86,30 @@ class CodeMirrorWidget extends Widget {
|
|
|
* A message handler invoked on an `'after-attach'` message.
|
|
|
*/
|
|
|
protected onAfterAttach(msg: Message): void {
|
|
|
- this.node.addEventListener('mousedown', this);
|
|
|
this.node.addEventListener('focus', this, true);
|
|
|
- this.node.addEventListener('blur', this, true);
|
|
|
+ if (!this.isVisible) {
|
|
|
+ this._needsRefresh = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this._editor.refresh();
|
|
|
+ this._needsRefresh = false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Handle `before_detach` messages for the widget.
|
|
|
*/
|
|
|
protected onBeforeDetach(msg: Message): void {
|
|
|
- this.node.removeEventListener('mousedown', this);
|
|
|
this.node.removeEventListener('focus', this, true);
|
|
|
- this.node.removeEventListener('blur', this, true);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Handle `mousedown` events for the widget.
|
|
|
- */
|
|
|
- private _evtMouseDown(event: MouseEvent): void {
|
|
|
- if (this._live.isVisible) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this._lastMouseDown = event;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Handle `focus` events for the widget.
|
|
|
- */
|
|
|
- private _evtFocus(event: FocusEvent): void {
|
|
|
- this._activate();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Handle `blur` events for the widget.
|
|
|
- */
|
|
|
- private _evtBlur(event: FocusEvent): void {
|
|
|
- this._lastMouseDown = null;
|
|
|
- if (this.node.contains(event.relatedTarget as HTMLElement)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this._live.hide();
|
|
|
- this._static.show();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Handle an activation message or a focus event.
|
|
|
- */
|
|
|
- private _activate(): void {
|
|
|
- let editor = this.editor;
|
|
|
- if (editor.getOption('readOnly') !== false) {
|
|
|
- this._lastMouseDown = null;
|
|
|
- return;
|
|
|
- }
|
|
|
- this._static.hide();
|
|
|
- this._live.show();
|
|
|
- if (this._lastMouseDown) {
|
|
|
- let x = this._lastMouseDown.clientX;
|
|
|
- let y = this._lastMouseDown.clientY;
|
|
|
- let pos = editor.coordsChar({ left: x, top: y });
|
|
|
- editor.getDoc().setCursor(pos);
|
|
|
- }
|
|
|
- editor.focus();
|
|
|
- }
|
|
|
-
|
|
|
- private _live: LiveCodeMirror;
|
|
|
- private _static: StaticCodeMirror;
|
|
|
- private _lastMouseDown: MouseEvent;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * A widget that hosts a codemirror instance.
|
|
|
- */
|
|
|
-class LiveCodeMirror extends Widget {
|
|
|
- /**
|
|
|
- * Construct a live codemirror.
|
|
|
- */
|
|
|
- constructor(options: CodeMirror.EditorConfiguration) {
|
|
|
- super();
|
|
|
- this.addClass(LIVE_CLASS);
|
|
|
- this._editor = CodeMirror(this.node, options);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Dispose of the resources held by the widget.
|
|
|
- */
|
|
|
- dispose(): void {
|
|
|
- this._editor = null;
|
|
|
- super.dispose();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Get the editor wrapped by the widget.
|
|
|
- */
|
|
|
- get editor(): CodeMirror.Editor {
|
|
|
- return this._editor;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* A message handler invoked on an `'after-show'` message.
|
|
|
*/
|
|
|
protected onAfterShow(msg: Message): void {
|
|
|
- this._editor.refresh();
|
|
|
+ if (this._needsRefresh) {
|
|
|
+ this._editor.refresh();
|
|
|
+ this._needsRefresh = false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -226,66 +117,36 @@ class LiveCodeMirror extends Widget {
|
|
|
*/
|
|
|
protected onResize(msg: ResizeMessage): void {
|
|
|
if (msg.width < 0 || msg.height < 0) {
|
|
|
- this._editor.refresh();
|
|
|
+ if (this._resizing === -1) {
|
|
|
+ this._resizing = setTimeout(() => {
|
|
|
+ this._editor.setSize(null, null);
|
|
|
+ this._resizing = -1;
|
|
|
+ }, 500);
|
|
|
+ }
|
|
|
} else {
|
|
|
this._editor.setSize(msg.width, msg.height);
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- private _editor: CodeMirror.Editor = null;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * A widget that holds rendered codemirror text.
|
|
|
- */
|
|
|
-class StaticCodeMirror extends Widget {
|
|
|
- /**
|
|
|
- * Construct a new static code mirror widget.
|
|
|
- */
|
|
|
- constructor(editor: CodeMirror.Editor) {
|
|
|
- super({ node: document.createElement('pre') });
|
|
|
- this._editor = editor;
|
|
|
- this.addClass(`cm-s-${editor.getOption('theme')}`);
|
|
|
- this.addClass('CodeMirror');
|
|
|
- this.addClass(STATIC_CLASS);
|
|
|
- CodeMirror.on(this._editor.getDoc(), 'change', (instance, change) => {
|
|
|
- if (this.isVisible) {
|
|
|
- this._render();
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Dispose of the resources held by the widget.
|
|
|
- */
|
|
|
- dispose(): void {
|
|
|
- this._editor = null;
|
|
|
- super.dispose();
|
|
|
+ this._needsRefresh = true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A message handler invoked on an `'after-attach'` message.
|
|
|
- */
|
|
|
- protected onAfterAttach(msg: Message): void {
|
|
|
- this._render();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * A message handler invoked on an `'after-show'` message.
|
|
|
+ * Handle `'activate-request'` messages.
|
|
|
*/
|
|
|
- protected onAfterShow(msg: Message): void {
|
|
|
- this._render();
|
|
|
+ protected onActivateRequest(msg: Message): void {
|
|
|
+ this._editor.focus();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Render the static content.
|
|
|
+ * Handle `focus` events for the widget.
|
|
|
*/
|
|
|
- private _render(): void {
|
|
|
- CodeMirror.runMode(this._editor.getDoc().getValue(),
|
|
|
- this._editor.getOption('mode'),
|
|
|
- this.node);
|
|
|
+ private _evtFocus(event: FocusEvent): void {
|
|
|
+ if (this._needsRefresh) {
|
|
|
+ this._editor.refresh();
|
|
|
+ this._needsRefresh = false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private _editor: CodeMirror.Editor = null;
|
|
|
+ private _needsRefresh = true;
|
|
|
+ private _resizing = -1;
|
|
|
}
|