|
|
import React, { Component } from 'react';
|
|
|
|
|
|
import Dialog, {
|
|
|
DialogActions,
|
|
|
DialogContent,
|
|
|
DialogContentText,
|
|
|
DialogTitle,
|
|
|
} from 'material-ui/Dialog';
|
|
|
import _ from 'lodash'
|
|
|
import Drawer from 'material-ui/Drawer';
|
|
|
|
|
|
import './TPIMonaco.css'
|
|
|
import TPICodeSetting from '../TPICodeSetting'
|
|
|
|
|
|
import * as monaco from 'monaco-editor'
|
|
|
|
|
|
|
|
|
import { fromStore, toStore } from 'educoder'
|
|
|
import './TPIMonacoConfig'
|
|
|
monaco.editor.defineTheme('myCoolTheme', {
|
|
|
base: 'vs-dark',
|
|
|
inherit: true,
|
|
|
rules: [
|
|
|
{ token: 'green', background: 'FF0000', foreground: '00FF00', fontStyle: 'italic'},
|
|
|
{ token: 'red', foreground: 'FF0000' , fontStyle: 'bold underline'},
|
|
|
{ background: '#121c23' },
|
|
|
// { foreground: 'FFFFFF' }
|
|
|
],
|
|
|
// editor_monaco._themeService._knownThemes.get('myCoolTheme')
|
|
|
colors: {
|
|
|
// 'editor.foreground': '#FFFFFF',
|
|
|
'editor.background': '#121c23',
|
|
|
|
|
|
// 'editor.selectionHighlightBorder': '#ffffff',
|
|
|
// 'input.border': '#ffffff',
|
|
|
'editor.lineHighlightBorder': '#222c34', // .current-line
|
|
|
|
|
|
}
|
|
|
});
|
|
|
|
|
|
const $ = window.$;
|
|
|
function loadMonacoResouce(callback) {
|
|
|
let _url_origin = ``;
|
|
|
let prefix = 'react/build'
|
|
|
if (window.location.port == 3007) {
|
|
|
prefix = ''
|
|
|
} else {
|
|
|
// _url_origin = `https://testeduplus2.educoder.net/`;
|
|
|
_url_origin = 'http://pre-newweb.educoder.net';
|
|
|
}
|
|
|
const $ = window.$;
|
|
|
|
|
|
if (!window['monaco']) {
|
|
|
// How to import this library in a create-react-app?
|
|
|
// https://github.com/Microsoft/monaco-editor/issues/82
|
|
|
// window.require = { paths: { 'vs': '../node_modules/monaco-editor/min/vs' } };
|
|
|
// window.require = { paths: { 'vs': `${_url_origin}${prefix}/js/monaco/vs` } };
|
|
|
|
|
|
// $('head').append($('<link rel="stylesheet" type="text/css" />')
|
|
|
// .attr('href', `${_url_origin}${prefix}/js/monaco/vs/editor/editor.main.css`));
|
|
|
|
|
|
// $.ajaxSetup({
|
|
|
// cache: true
|
|
|
// });
|
|
|
// $.when(
|
|
|
|
|
|
// // $.getScript( `${_url_origin}${prefix}/js/monaco/vs/language/typescript/tsMode.js` ),
|
|
|
// // $.getScript( `${_url_origin}${prefix}/js/monaco/vs/basic-languages/javascript/javascript.js` ),
|
|
|
// $.getScript( `${_url_origin}${prefix}/js/monaco/vs/basic-languages/python/python.js` ),
|
|
|
// // $.getScript( `${_url_origin}${prefix}/js/monaco/vs/language/typescript/tsWorker.js` ),
|
|
|
|
|
|
// $.getScript( `${_url_origin}${prefix}/js/monaco/vs/loader.js` ),
|
|
|
// $.getScript( `${_url_origin}${prefix}/js/monaco/vs/editor/editor.main.nls.js` ),
|
|
|
// $.getScript( `${_url_origin}${prefix}/js/monaco/vs/editor/editor.main.js` ),
|
|
|
// $.Deferred(function( deferred ){
|
|
|
// console.log('Deferred')
|
|
|
|
|
|
// // TODO 暂时放这里
|
|
|
// $( deferred.resolve );
|
|
|
// checkIfLoaded(callback);
|
|
|
|
|
|
// })
|
|
|
// ).done(function(){
|
|
|
// debugger;
|
|
|
// // TODO 没执行到这里
|
|
|
// console.log('done done done ')
|
|
|
// //place your code here, the scripts are all loaded
|
|
|
// // callback && callback()
|
|
|
// });
|
|
|
|
|
|
// require.config({ paths: { 'vs': `/monaco/vs` }});
|
|
|
|
|
|
// require(['/vs/editor/editor.main'], function() {
|
|
|
callback && callback()
|
|
|
var editor = monaco.editor.create(document.getElementById('container'), {
|
|
|
value: [
|
|
|
'function x() {',
|
|
|
'\tconsole.log("Hello world!");',
|
|
|
'}'
|
|
|
].join('\n'),
|
|
|
language: 'javascript'
|
|
|
});
|
|
|
// });
|
|
|
|
|
|
} else {
|
|
|
callback && callback()
|
|
|
}
|
|
|
}
|
|
|
function checkIfLoaded (callback) {
|
|
|
if (window.monaco && window.monaco.editor) {
|
|
|
$.ajaxSetup({
|
|
|
cache: false
|
|
|
});
|
|
|
callback && callback()
|
|
|
} else {
|
|
|
console.log('check again 2s later..')
|
|
|
setTimeout(() => {
|
|
|
checkIfLoaded(callback)
|
|
|
}, 2000);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
language
|
|
|
javascript css less scss html typescript
|
|
|
java ruby vb r python php perl go cpp csharp
|
|
|
sql pgsql mysql
|
|
|
swift objective-c
|
|
|
shell
|
|
|
redis
|
|
|
xml yaml
|
|
|
markdown
|
|
|
|
|
|
'JFinal': 'text/x-java',
|
|
|
'Java': 'text/x-java',
|
|
|
'Kotlin': 'text/x-kotlin',
|
|
|
'C/C++' : 'text/x-c++src',
|
|
|
'MachineLearning': {
|
|
|
name: "python",
|
|
|
version: 3,
|
|
|
singleLineStringErrors: false
|
|
|
},
|
|
|
'Python2.7': {
|
|
|
name: "python",
|
|
|
version: 3,
|
|
|
singleLineStringErrors: false
|
|
|
},
|
|
|
'Python3.6': {
|
|
|
name: "python",
|
|
|
version: 3,
|
|
|
singleLineStringErrors: false
|
|
|
},
|
|
|
*/
|
|
|
const mirror2LanguageMap = {
|
|
|
'JFinal': 'java',
|
|
|
'Java': 'java',
|
|
|
'JavaWeb': 'java',
|
|
|
'Kotlin': 'java',
|
|
|
|
|
|
'Html': 'html',
|
|
|
'Css': 'css',
|
|
|
'Javascript': 'javascript',
|
|
|
'JavaScript': 'javascript',
|
|
|
|
|
|
'C/C++': 'cpp',
|
|
|
'MachineLearning': 'python',
|
|
|
'Python2.7': 'python',
|
|
|
'Python3.6': 'python',
|
|
|
|
|
|
'C#': 'csharp',
|
|
|
'R': 'r'
|
|
|
|
|
|
}
|
|
|
function getLanguageByMirrorName(mirror_name) {
|
|
|
let lang = 'javascript'
|
|
|
if (mirror_name && mirror_name.length) {
|
|
|
// 需要倒着遍历, html、css的实训,主评测语言环境是python,小类别是html或css
|
|
|
// TODO http://localhost:3007/tasks/hmcwa3g8typ5?debug=t ["Python3.6", "VNC", "Html"]
|
|
|
for (let i = mirror_name.length - 1; i >= 0; i--) {
|
|
|
let languageVal = mirror2LanguageMap[mirror_name[i]];
|
|
|
if (languageVal) {
|
|
|
lang = languageVal;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return lang;
|
|
|
}
|
|
|
|
|
|
let notCallCodeMirrorOnChangeFlag = false;
|
|
|
|
|
|
/**
|
|
|
props :
|
|
|
mirror_name 决定语言
|
|
|
isEditablePath
|
|
|
repositoryCode
|
|
|
|
|
|
codemirrorDidMount
|
|
|
|
|
|
shixun.forbid_copy
|
|
|
|
|
|
showSettingDrawer, settingDrawerOpen
|
|
|
*/
|
|
|
class TPIMonaco extends Component {
|
|
|
|
|
|
constructor(props) {
|
|
|
super(props)
|
|
|
|
|
|
loadMonacoResouce();
|
|
|
this.state = {
|
|
|
cmFontSize: fromStore('cmFontSize', 16),
|
|
|
autoCompleteSwitch: fromStore('autoCompleteSwitch', true),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
|
const { mirror_name } = this.props
|
|
|
const editor_monaco = this.editor_monaco;
|
|
|
if (editor_monaco && !_.isEqual(prevProps.mirror_name, mirror_name)) {
|
|
|
// TODO 后期考虑加入,根据文件类型的不同,使用不同的lang
|
|
|
const lang = getLanguageByMirrorName(mirror_name);
|
|
|
// https://github.com/Microsoft/monaco-editor/issues/539
|
|
|
window.monaco.editor.setModelLanguage(editor_monaco.getModel(), lang)
|
|
|
} else if (prevProps.isEditablePath != this.props.isEditablePath) {
|
|
|
if (this.props.isEditablePath || this.props.shixun && this.props.shixun.code_edit_permission == true) {
|
|
|
editor_monaco.updateOptions({readOnly: false})
|
|
|
} else {
|
|
|
editor_monaco.updateOptions({readOnly: true})
|
|
|
}
|
|
|
|
|
|
} else if (editor_monaco && prevProps.codeLoading === true && this.props.codeLoading === false
|
|
|
) {
|
|
|
if (this.props.repositoryCode != editor_monaco.getValue()) {
|
|
|
// newProps.repositoryCode !== this.props.repositoryCode &&
|
|
|
notCallCodeMirrorOnChangeFlag = true;
|
|
|
|
|
|
// 重要:setState(因获取代码、重置代码等接口引起的调用)调用引起的变化才需要setValue
|
|
|
editor_monaco.setValue(this.props.repositoryCode)
|
|
|
}
|
|
|
// 代码没变也需要layout,可能从命令行自动切回了代码tab
|
|
|
editor_monaco.layout();
|
|
|
|
|
|
// Clears the editor's undo history.
|
|
|
// TODO
|
|
|
// extend_editor.clearHistory()
|
|
|
}
|
|
|
}
|
|
|
componentWillUnmount() {
|
|
|
this.editor_monaco && this.editor_monaco.dispose()
|
|
|
}
|
|
|
|
|
|
componentDidMount() {
|
|
|
checkIfLoaded(() => {
|
|
|
let value = [
|
|
|
'define([], function() {',
|
|
|
'\treturn ({p1, p2}) => {',
|
|
|
'\t\treturn Promise.resolve("Hello, World");',
|
|
|
'\t};',
|
|
|
'});'
|
|
|
].join('\n');
|
|
|
// value = [
|
|
|
// 'function x() {',
|
|
|
// '\tconsole.log("Hello world!");',
|
|
|
// '}'
|
|
|
// ].join('\n'),
|
|
|
value = "<h1>Hello</h1>↵<!-- ********* Begin ********* -->↵ ↵ ↵<!-- ********* End ********* -->"
|
|
|
|
|
|
value = this.props.repositoryCode
|
|
|
|
|
|
const height = $('#games_repository_contents').height() - 40
|
|
|
const width = $('#games_repository_contents').width()
|
|
|
|
|
|
$('#codetab_con_1').height(height)
|
|
|
|
|
|
const lang = getLanguageByMirrorName(this.props.mirror_name);
|
|
|
const editor = window.monaco.editor.create(document.getElementById('extend-challenge-file-edit'), {
|
|
|
value: value,
|
|
|
readOnly: !this.props.isEditablePath && this.props.shixun && this.props.shixun.code_edit_permission != true,
|
|
|
// 属性说明
|
|
|
// http://testeduplus2.educoder.net/react/build/static/node_modules/_monaco-editor@0.15.6@monaco-editor/esm/vs/editor/common/config/commonEditorConfig.js
|
|
|
// https://github.com/Microsoft/monaco-editor/issues/29
|
|
|
scrollBeyondLastLine: false,
|
|
|
|
|
|
language: lang,
|
|
|
// language: 'css',
|
|
|
|
|
|
// theme: "vs-dark",
|
|
|
theme: "myCoolTheme",
|
|
|
fontSize: this.state.cmFontSize
|
|
|
|
|
|
});
|
|
|
|
|
|
window.editor_monaco = editor;
|
|
|
this.editor_monaco = editor
|
|
|
|
|
|
// editor.setPosition({ lineNumber: 2, column: 30 });
|
|
|
|
|
|
// editor.model.onDidChangeContent((event) => {
|
|
|
// if (notCallCodeMirrorOnChangeFlag === true) {
|
|
|
// notCallCodeMirrorOnChangeFlag = false
|
|
|
// return;
|
|
|
// }
|
|
|
// this.props.onRepositoryCodeUpdate(editor.getValue())
|
|
|
// });
|
|
|
|
|
|
editor.onDidChangeModelContent((event) => {
|
|
|
if (notCallCodeMirrorOnChangeFlag === true) {
|
|
|
notCallCodeMirrorOnChangeFlag = false
|
|
|
return;
|
|
|
}
|
|
|
this.props.onRepositoryCodeUpdate && this.props.onRepositoryCodeUpdate(editor.getValue())
|
|
|
})
|
|
|
this.props.codemirrorDidMount && this.props.codemirrorDidMount()
|
|
|
|
|
|
if(this.props.shixun && this.props.shixun.forbid_copy == true) {
|
|
|
// 禁用粘贴
|
|
|
// https://github.com/Microsoft/monaco-editor/issues/100
|
|
|
window.editor_monaco.onDidPaste( (a, b, c) => { window.__pastePosition = a })
|
|
|
window.addEventListener('paste', (a, b, c) => {
|
|
|
const selection = window.editor_monaco.getSelection();
|
|
|
const range = new monaco.Range(
|
|
|
window.__pastePosition.startLineNumber || selection.endLineNumber,
|
|
|
window.__pastePosition.startColumn || selection.endColumn,
|
|
|
window.__pastePosition.endLineNumber || selection.endLineNumber,
|
|
|
window.__pastePosition.endColumn || selection.endColumn,);
|
|
|
window.editor_monaco.executeEdits('', [{range, text: ''}] )
|
|
|
|
|
|
})
|
|
|
|
|
|
// 禁用复制
|
|
|
window.editor_monaco.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_C, () => null);
|
|
|
window.editor_monaco.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_V, () => null);
|
|
|
}
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
editor.layout();
|
|
|
editor.focus();
|
|
|
}, 600)
|
|
|
|
|
|
window.editor_monaco.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S, () => {
|
|
|
this.props.doFileUpdateRequestOnCodeMirrorBlur();
|
|
|
return false;
|
|
|
});
|
|
|
})
|
|
|
|
|
|
// window.document.onkeydown = (e) => {
|
|
|
// e = window.event || e;
|
|
|
// if(e.keyCode== 83 && e.ctrlKey){
|
|
|
// /*延迟,兼容FF浏览器 */
|
|
|
// // setTimeout(function(){
|
|
|
// // alert('ctrl+s');
|
|
|
// // },1);
|
|
|
// this.props.doFileUpdateRequestOnCodeMirrorBlur();
|
|
|
// return false;
|
|
|
// }
|
|
|
// };
|
|
|
}
|
|
|
onFontSizeChange = (value) => {
|
|
|
toStore('cmFontSize', value)
|
|
|
this.editor_monaco.updateOptions({fontSize: value})
|
|
|
|
|
|
this.setState({ cmFontSize: value });
|
|
|
}
|
|
|
onAutoCompleteSwitchChange = () => {
|
|
|
|
|
|
}
|
|
|
render() {
|
|
|
const { repositoryCode, showSettingDrawer, settingDrawerOpen } = this.props;
|
|
|
const { cmFontSize } = this.state;
|
|
|
|
|
|
return (
|
|
|
<React.Fragment>
|
|
|
<Drawer
|
|
|
anchor="right"
|
|
|
|
|
|
className="settingDrawer"
|
|
|
|
|
|
width={260}
|
|
|
open={settingDrawerOpen}
|
|
|
|
|
|
onClose={() => showSettingDrawer( false )}
|
|
|
>
|
|
|
<TPICodeSetting {...this.props} {...this.state}
|
|
|
onFontSizeChange={this.onFontSizeChange}
|
|
|
onAutoCompleteSwitchChange={this.onAutoCompleteSwitchChange}
|
|
|
></TPICodeSetting>
|
|
|
</Drawer>
|
|
|
<div className = "" id="extend-challenge-file-edit" name="content"
|
|
|
style={{ width: '100%', height: '100%', border:'1px solid grey' }}></div>
|
|
|
</React.Fragment>
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
export default ( TPIMonaco ) ;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
// http://testeduplus2.educoder.net/react/build/static/node_modules/
|
|
|
_monaco-editor@0.15.6@monaco-editor/esm/vs/editor/common/config/editorOptions.js
|
|
|
export var EDITOR_DEFAULTS = {
|
|
|
inDiffEditor: false,
|
|
|
wordSeparators: USUAL_WORD_SEPARATORS,
|
|
|
lineNumbersMinChars: 5,
|
|
|
lineDecorationsWidth: 10,
|
|
|
readOnly: false,
|
|
|
mouseStyle: 'text',
|
|
|
disableLayerHinting: false,
|
|
|
automaticLayout: false,
|
|
|
wordWrap: 'off',
|
|
|
wordWrapColumn: 80,
|
|
|
wordWrapMinified: true,
|
|
|
wrappingIndent: 1
|
|
|
wordWrapBreakBeforeCharacters: '([{‘“〈《「『【〔([{「£¥$£¥++',
|
|
|
wordWrapBreakAfterCharacters: ' \t})]?|&,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」',
|
|
|
wordWrapBreakObtrusiveCharacters: '.',
|
|
|
autoClosingBrackets: 'languageDefined',
|
|
|
autoClosingQuotes: 'languageDefined',
|
|
|
autoSurround: 'languageDefined',
|
|
|
autoIndent: true,
|
|
|
dragAndDrop: true,
|
|
|
emptySelectionClipboard: true,
|
|
|
copyWithSyntaxHighlighting: true,
|
|
|
useTabStops: true,
|
|
|
multiCursorModifier: 'altKey',
|
|
|
multiCursorMergeOverlapping: true,
|
|
|
accessibilitySupport: 'auto',
|
|
|
showUnused: true,
|
|
|
viewInfo: {
|
|
|
extraEditorClassName: '',
|
|
|
disableMonospaceOptimizations: false,
|
|
|
rulers: [],
|
|
|
ariaLabel: nls.localize('editorViewAccessibleLabel', "Editor content"),
|
|
|
renderLineNumbers: 1 // On ,
|
|
|
renderCustomLineNumbers: null,
|
|
|
selectOnLineNumbers: true,
|
|
|
glyphMargin: true,
|
|
|
revealHorizontalRightPadding: 30,
|
|
|
roundedSelection: true,
|
|
|
overviewRulerLanes: 2,
|
|
|
overviewRulerBorder: true,
|
|
|
cursorBlinking: 1 /* Blink ,
|
|
|
mouseWheelZoom: false,
|
|
|
cursorStyle: TextEditorCursorStyle.Line,
|
|
|
cursorWidth: 0,
|
|
|
hideCursorInOverviewRuler: false,
|
|
|
scrollBeyondLastLine: true,
|
|
|
scrollBeyondLastColumn: 5,
|
|
|
smoothScrolling: false,
|
|
|
stopRenderingLineAfter: 10000,
|
|
|
renderWhitespace: 'none',
|
|
|
renderControlCharacters: false,
|
|
|
fontLigatures: false,
|
|
|
renderIndentGuides: true,
|
|
|
highlightActiveIndentGuide: true,
|
|
|
renderLineHighlight: 'line',
|
|
|
scrollbar: {
|
|
|
vertical: 1 /* Auto ,
|
|
|
horizontal: 1 /* Auto ,
|
|
|
arrowSize: 11,
|
|
|
useShadows: true,
|
|
|
verticalHasArrows: false,
|
|
|
horizontalHasArrows: false,
|
|
|
horizontalScrollbarSize: 10,
|
|
|
horizontalSliderSize: 10,
|
|
|
verticalScrollbarSize: 14,
|
|
|
verticalSliderSize: 14,
|
|
|
handleMouseWheel: true,
|
|
|
mouseWheelScrollSensitivity: 1,
|
|
|
},
|
|
|
minimap: {
|
|
|
enabled: true,
|
|
|
side: 'right',
|
|
|
showSlider: 'mouseover',
|
|
|
renderCharacters: true,
|
|
|
maxColumn: 120
|
|
|
},
|
|
|
fixedOverflowWidgets: false,
|
|
|
},
|
|
|
contribInfo: {
|
|
|
selectionClipboard: true,
|
|
|
hover: {
|
|
|
enabled: true,
|
|
|
delay: 300,
|
|
|
sticky: true
|
|
|
},
|
|
|
links: true,
|
|
|
contextmenu: true,
|
|
|
quickSuggestions: { other: true, comments: false, strings: false },
|
|
|
quickSuggestionsDelay: 10,
|
|
|
parameterHints: {
|
|
|
enabled: true,
|
|
|
cycle: false
|
|
|
},
|
|
|
iconsInSuggestions: true,
|
|
|
formatOnType: false,
|
|
|
formatOnPaste: false,
|
|
|
suggestOnTriggerCharacters: true,
|
|
|
acceptSuggestionOnEnter: 'on',
|
|
|
acceptSuggestionOnCommitCharacter: true,
|
|
|
wordBasedSuggestions: true,
|
|
|
suggestSelection: 'recentlyUsed',
|
|
|
suggestFontSize: 0,
|
|
|
suggestLineHeight: 0,
|
|
|
tabCompletion: 'off',
|
|
|
suggest: {
|
|
|
filterGraceful: true,
|
|
|
snippets: 'inline',
|
|
|
snippetsPreventQuickSuggestions: true,
|
|
|
localityBonus: false
|
|
|
},
|
|
|
selectionHighlight: true,
|
|
|
occurrencesHighlight: true,
|
|
|
codeLens: true,
|
|
|
folding: true,
|
|
|
foldingStrategy: 'auto',
|
|
|
showFoldingControls: 'mouseover',
|
|
|
matchBrackets: true,
|
|
|
find: {
|
|
|
seedSearchStringFromSelection: true,
|
|
|
autoFindInSelection: false,
|
|
|
globalFindClipboard: false
|
|
|
},
|
|
|
colorDecorators: true,
|
|
|
lightbulbEnabled: true,
|
|
|
codeActionsOnSave: {},
|
|
|
codeActionsOnSaveTimeout: 750
|
|
|
},
|
|
|
};
|
|
|
|
|
|
|
|
|
*/ |