siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
648 lines (572 loc) • 24.3 kB
HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The source code</title>
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
<style type="text/css">
.highlight { display: block; background-color: #ddd; }
</style>
<script type="text/javascript">
function highlight() {
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
}
</script>
</head>
<body onload="prettyPrint(); highlight();">
<pre class="prettyprint lang-js">/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
Ext.define('Ext.ux.form.field.CodeMirror', {
extend : 'Ext.Component',
alias : 'widget.jseditor',
alternateClassName : 'Ext.form.CodeMirror',
requires : [
'Ext.tip.QuickTipManager',
'Ext.toolbar.Item',
'Ext.util.Format'
],
width : '100%',
<span id='global-cfg-mode'> /**
</span> * @cfg {String} mode The default mode to use when the editor is initialized. When not given, this will default to the first mode that was loaded.
* It may be a string, which either simply names the mode or is a MIME type associated with the mode. Alternatively,
* it may be an object containing configuration options for the mode, with a name property that names the mode
* (for example {name: "javascript", json: true}). The demo pages for each mode contain information about what
* configuration parameters the mode supports.
*/
mode : 'text/javascript',
<span id='global-cfg-showLineNumbers'> /**
</span> * @cfg {Boolean} showLineNumbers Enable line numbers button in the toolbar.
*/
showLineNumbers : true,
<span id='global-cfg-enableMatchBrackets'> /**
</span> * @cfg {Boolean} enableMatchBrackets Force matching-bracket-highlighting to happen
*/
enableMatchBrackets : true,
<span id='global-cfg-enableElectricChars'> /**
</span> * @cfg {Boolean} enableElectricChars Configures whether the editor should re-indent the current line when a character is typed
* that might change its proper indentation (only works if the mode supports indentation).
*/
enableElectricChars : false,
<span id='global-cfg-enableIndentWithTabs'> /**
</span> * @cfg {Boolean} enableIndentWithTabs Whether, when indenting, the first N*tabSize spaces should be replaced by N tabs.
*/
enableIndentWithTabs : true,
<span id='global-cfg-enableSmartIndent'> /**
</span> * @cfg {Boolean} enableSmartIndent Whether to use the context-sensitive indentation that the mode provides (or just indent the same as the line before).
*/
enableSmartIndent : true,
<span id='global-cfg-enableLineWrapping'> /**
</span> * @cfg {Boolean} enableLineWrapping Whether CodeMirror should scroll or wrap for long lines.
*/
enableLineWrapping : false,
<span id='global-cfg-enableLineNumbers'> /**
</span> * @cfg {Boolean} enableLineNumbers Whether to show line numbers to the left of the editor.
*/
enableLineNumbers : true,
<span id='global-cfg-enableFixedGutter'> /**
</span> * @cfg {Boolean} enableFixedGutter When enabled (off by default), this will make the gutter stay visible when the
* document is scrolled horizontally.
*/
enableFixedGutter : false,
<span id='global-cfg-firstLineNumber'> /**
</span> * @cfg {Number} firstLineNumber At which number to start counting lines.
*/
firstLineNumber : 1,
<span id='global-cfg-readOnly'> /**
</span> * @cfg {Boolean} readOnly <tt>true</tt> to mark the field as readOnly.
*/
readOnly : false,
<span id='global-cfg-pollInterval'> /**
</span> * @cfg {Number} pollInterval Indicates how quickly (miliseconds) CodeMirror should poll its input textarea for changes.
* Most input is captured by events, but some things, like IME input on some browsers, doesn't generate events
* that allow CodeMirror to properly detect it. Thus, it polls.
*/
pollInterval : 100,
<span id='global-cfg-indentUnit'> /**
</span> * @cfg {Number} indentUnit How many spaces a block (whatever that means in the edited language) should be indented.
*/
indentUnit : 4,
<span id='global-cfg-tabSize'> /**
</span> * @cfg {Number} tabSize The width of a tab character.
*/
tabSize : 4,
<span id='global-cfg-theme'> /**
</span> * @cfg {String} theme The theme to style the editor with. You must make sure the CSS file defining the corresponding
* .cm-s-[name] styles is loaded (see the theme directory in the distribution). The default is "default", for which
* colors are included in codemirror.css. It is possible to use multiple theming classes at once—for example
* "foo bar" will assign both the cm-s-foo and the cm-s-bar classes to the editor.
*/
theme : 'default',
scriptsLoaded : [],
lastMode : '',
initComponent : function () {
var me = this;
//me.addEvents(
<span id='global-event-initialize'> /**
</span> * @event initialize
* Fires when the editor is fully initialized (including the iframe)
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'initialize',
<span id='global-event-activate'> /**
</span> * @event activate
* Fires when the editor is first receives the focus. Any insertion must wait
* until after this event.
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'activate',
<span id='global-event-deactivate'> /**
</span> * @event deactivate
* Fires when the editor looses the focus.
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'deactivate',
<span id='global-event-change'> /**
</span> * @event change
* Fires when the content of the editor is changed.
* @param {Ext.ux.form.field.CodeMirror} this
* @param {String} newValue New value
* @param {String} oldValue Old value
* @param {Array} options
*/
//'change',
<span id='global-event-cursoractivity'> /**
</span> * @event cursoractivity
* Fires when the cursor or selection moves, or any change is made to the editor content.
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'cursoractivity',
<span id='global-event-gutterclick'> /**
</span> * @event gutterclick
* Fires whenever the editor gutter (the line-number area) is clicked.
* @param {Ext.ux.form.field.CodeMirror} this
* @param {Number} lineNumber Zero-based number of the line that was clicked
* @param {Object} event The raw mousedown event
*/
//'gutterclick',
<span id='global-event-scroll'> /**
</span> * @event scroll
* Fires whenever the editor is scrolled.
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'scroll',
<span id='global-event-highlightcomplete'> /**
</span> * @event highlightcomplete
* Fires whenever the editor's content has been fully highlighted.
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'highlightcomplete',
<span id='global-event-update'> /**
</span> * @event update
* Fires whenever CodeMirror updates its DOM display.
* @param {Ext.ux.form.field.CodeMirror} this
*/
//'update',
<span id='global-event-keyevent'> /**
</span> * @event keyevent
* Fires on eery keydown, keyup, and keypress event that CodeMirror captures.
* @param {Ext.ux.form.field.CodeMirror} this
* @param {Object} event This key event is pretty much the raw key event, except that a stop() method is always
* added to it. You could feed it to, for example, jQuery.Event to further normalize it. This function can inspect
* the key event, and handle it if it wants to. It may return true to tell CodeMirror to ignore the event.
* Be wary that, on some browsers, stopping a keydown does not stop the keypress from firing, whereas on others
* it does. If you respond to an event, you should probably inspect its type property and only do something when
* it is keydown (or keypress for actions that need character data).
*/
//'keyevent'
//);
me.callParent(arguments);
/*
Fix resize issues as suggested by user koblass on the Extjs forums
http://www.sencha.com/forum/showthread.php?167047-Ext.ux.form.field.CodeMirror-for-Ext-4.x&p=860535&viewfull=1#post860535
*/
me.on('resize', function () {
if (me.editor) {
me.editor.refresh();
}
}, me);
},
resetOriginalValue : Ext.emptyFn,
isValid : function() {
var errors = this.getErrors() || [];
return errors.length === 0;
},
<span id='global-method-afterRender'> /**
</span> * @private override
*/
afterRender : function () {
var me = this;
me.callParent(arguments);
me.initEditor();
},
<span id='global-method-initEditor'> /**
</span> * @private override
*/
initEditor : function () {
var me = this,
mode = 'javascript';
me.editor = CodeMirror(me.el.dom, {
matchBrackets : me.enableMatchBrackets,
electricChars : me.enableElectricChars,
autoClearEmptyLines : true,
indentUnit : me.indentUnit,
smartIndent : me.enableSmartIndent,
indentWithTabs : me.indentWithTabs,
pollInterval : me.pollInterval,
lineNumbers : me.enableLineNumbers,
lineWrapping : me.enableLineWrapping,
firstLineNumber : me.firstLineNumber,
tabSize : me.tabSize,
gutters : ["CodeMirror-lint-markers"],
fixedGutter : me.enableFixedGutter,
theme : me.theme,
mode : mode,
lintWith : CodeMirror.javascriptValidatorWithOptions({
"onecase" : true,
"asi" : true,
"expr" : true, // allow fn && fn()
"loopfunc" : true,
"laxbreak" : true,
"debug" : true,
"laxcomma" : true,
smarttabs : true
}),
onChange : function (editor, tc) {
me.checkValid();
//me.last-child();
//me.fireEvent('change', me, tc.from, tc.to, tc.text, tc.next || null);
},
onCursorActivity : function (editor) {
me.fireEvent('cursoractivity', me);
},
onGutterClick : function (editor, line, event) {
me.fireEvent('gutterclick', me, line, event);
},
onFocus : function (editor) {
me.fireEvent('activate', me);
},
onBlur : function (editor, e) {
me.fireEvent('deactivate', me);
me.onBlur(e);
},
onScroll : function (editor) {
me.fireEvent('scroll', me);
},
onHighlightComplete : function (editor) {
me.fireEvent('highlightcomplete', me);
},
onUpdate : function (editor) {
me.fireEvent('update', me);
},
onKeyEvent : function (editor, event) {
event.cancelBubble = true; // fix suggested by koblass user on Sencha forums (http://www.sencha.com/forum/showthread.php?167047-Ext.ux.form.field.CodeMirror-for-Ext-4.x&p=862029&viewfull=1#post862029)
me.fireEvent('keyevent', me, event);
}
});
//me.editor.setValue(me.rawValue);
// me.setMode(me.mode);
me.setReadOnly(me.readOnly);
me.fireEvent('initialize', me);
// change the codemirror css
var css = Ext.util.CSS.getRule('.CodeMirror');
if (css) {
css.style.height = '100%';
css.style.position = 'relative';
css.style.overflow = 'hidden';
}
var css = Ext.util.CSS.getRule('.CodeMirror-Scroll');
if (css) {
css.style.height = '100%';
}
},
checkValid : function() {
var errors = this.getErrors() || [];
if (errors.length > 0) {
this.addCls('siesta-invalid-syntax');
} else {
this.removeCls('siesta-invalid-syntax');
}
},
getErrors : function() {
},
<span id='global-method-relayBtnCmd'> /**
</span> * @private
*/
relayBtnCmd : function (btn) {
this.relayCmd(btn.getItemId());
},
<span id='global-method-relayCmd'> /**
</span> * @private
*/
relayCmd : function (cmd) {
Ext.defer(function () {
var me = this;
me.editor.focus();
switch (cmd) {
// auto formatting
case 'justifycenter':
if (!CodeMirror.extensions.autoIndentRange) {
me.loadDependencies(me.extensions.format, me.pathExtensions, me.doIndentSelection, me);
} else {
me.doIndentSelection();
}
break;
// line numbers
case 'insertorderedlist':
me.doChangeLineNumbers();
break;
}
}, 10, this);
},
doChangeLineNumbers : function () {
var me = this;
me.enableLineNumbers = !me.enableLineNumbers;
me.editor.setOption('lineNumbers', me.enableLineNumbers);
},
<span id='global-method-doIndentSelection'> /**
</span> * @private
*/
doIndentSelection : function () {
var me = this;
me.reloadExtentions();
try {
var range = { from : me.editor.getCursor(true), to : me.editor.getCursor(false) };
me.editor.autoIndentRange(range.from, range.to);
} catch (err) {
}
},
<span id='global-method-setReadOnly'> /**
</span> * Set the editor as read only
*
* @param {Boolean} readOnly
*/
setReadOnly : function (readOnly) {
var me = this;
if (me.editor) {
me.editor.setOption('readOnly', readOnly);
}
},
onDisable : function () {
this.bodyEl.mask();
this.callParent(arguments);
},
onEnable : function () {
this.bodyEl.unmask();
this.callParent(arguments);
},
<span id='global-method-setValue'> /**
</span> * Sets a data value into the field and runs the change detection.
* @param {Mixed} value The value to set
* @return {Ext.ux.form.field.CodeMirror} this
*/
setValue : function (value) {
value = value || '';
var me = this;
// me.mixins.field.setValue.call(me, value);
// me.rawValue = value;
if (me.editor) {
me.editor.setValue(value);
}
return me;
},
<span id='global-method-getSubmitValue'> /**
</span> * Return submit value to the owner form.
* @return {Mixed} The field value
*/
getSubmitValue : function () {
var me = this;
return me.getValue();
},
getRawValue : function () {
return this.getValue();
},
<span id='global-method-getValue'> /**
</span> * Return the value of the CodeMirror editor
* @return {Mixed} The field value
*/
getValue : function () {
var me = this;
if (me.editor)
return me.editor.getValue() || '';
else
return '';
},
<span id='global-method-onDestroy'> /**
</span> * @private
*/
onDestroy : function () {
var me = this;
if (me.rendered) {
for (var prop in me.editor) {
if (me.editor.hasOwnProperty(prop)) {
delete me.editor[prop];
}
}
Ext.destroyMembers('tb', 'toolbarWrap', 'editorEl');
}
me.callParent();
},
commentLine : function () {
var editor = this.editor;
var start = editor.getCursor(true);
var end = editor.getCursor(false);
var currentLine = start.line;
var doFormat = false;
function toggleCommented(line) {
text = editor.getLine(line);
if (text.match(/^\s*\/\/\s*/)) {
text = text.replace(/\s*\/\/\s*/, '');
doFormat = true;
} else {
text = text.substr(0, text.indexOf(Ext.String.trim(text))) + '// ' + Ext.String.trim(text);
}
editor.setLine(line, text);
}
if (start.line === end.line && start.ch === end.ch) {
toggleCommented(start.line);
} else if (start.character == 0) {
while (currentLine != end.line) {
toggleCommented(currentLine);
currentLine = editor.getLine(++currentLine);
}
editor.selectLines(start.line, start.ch, end.line, end.ch);
} else {
var text = editor.getSelection();
var diff = 1;
if (text.match(/^\/\*/) && text.match(/^\/\*/)) {
text = text.substring(2, text.length - 2);
diff = -1;
doFormat = true;
} else {
text = "/*" + text + "*/";
}
editor.replaceSelection(text);
// following line crash
// if (start.line == end.line) {
// editor.setSelection(start.line, start.ch, end.line, end.ch+(diff*4));
// } else {
// editor.setSelection(start.line, start.ch, end.line, end.ch+(diff*2));
// }
}
if (doFormat) {
editor.autoIndentRange({ line : 0 }, { line : editor.lineCount() });
}
}
});
//
//(function () {
// CodeMirror.extendMode("css", {
// commentStart : "/*",
// commentEnd : "*/",
// newlineAfterToken : function (type, content) {
// return /^[;{}]$/.test(content);
// }
// });
//
// CodeMirror.extendMode("javascript", {
// commentStart : "/*",
// commentEnd : "*/",
// // FIXME semicolons inside of for
// newlineAfterToken : function (type, content, textAfter, state) {
// if (this.jsonMode) {
// return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
// } else {
// if (content == ";" && state.lexical && state.lexical.type == ")") return false;
// return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
// }
// }
// });
//
// CodeMirror.extendMode("xml", {
// commentStart : "<!--",
// commentEnd : "-->",
// newlineAfterToken : function (type, content, textAfter) {
// return type == "tag" && />$/.test(content) || /^</.test(textAfter);
// }
// });
//
// // Comment/uncomment the specified range
// CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
// var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
// cm.operation(function () {
// if (isComment) { // Comment range
// cm.replaceRange(curMode.commentEnd, to);
// cm.replaceRange(curMode.commentStart, from);
// if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
// cm.setCursor(from.line, from.ch + curMode.commentStart.length);
// } else { // Uncomment range
// var selText = cm.getRange(from, to);
// var startIndex = selText.indexOf(curMode.commentStart);
// var endIndex = selText.lastIndexOf(curMode.commentEnd);
// if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
// // Take string till comment start
// selText = selText.substr(0, startIndex)
// // From comment start till comment end
// + selText.substring(startIndex + curMode.commentStart.length, endIndex)
// // From comment end till string end
// + selText.substr(endIndex + curMode.commentEnd.length);
// }
// cm.replaceRange(selText, from, to);
// }
// });
// });
//
// // Applies automatic mode-aware indentation to the specified range
// CodeMirror.defineExtension("autoIndentRange", function (from, to) {
// var cmInstance = this;
// this.operation(function () {
// for (var i = from.line; i <= to.line; i++) {
// cmInstance.indentLine(i, "smart");
// }
// });
// });
//
// // Applies automatic formatting to the specified range
// CodeMirror.defineExtension("autoFormatRange", function (from, to) {
// var cm = this;
// var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
// var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
// var tabSize = cm.getOption("tabSize");
//
// var out = "", lines = 0, atSol = from.ch == 0;
//
// function newline() {
// out += "\n";
// atSol = true;
// ++lines;
// }
//
// for (var i = 0; i < text.length; ++i) {
// var stream = new CodeMirror.StringStream(text[i], tabSize);
// while (!stream.eol()) {
// var inner = CodeMirror.innerMode(outer, state);
// var style = outer.token(stream, state), cur = stream.current();
// stream.start = stream.pos;
// if (!atSol || /\S/.test(cur)) {
// out += cur;
// atSol = false;
// }
// if (!atSol && inner.mode.newlineAfterToken &&
// inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i + 1] || "", inner.state))
// newline();
// }
// if (!stream.pos && outer.blankLine) outer.blankLine(state);
// if (!atSol) newline();
// }
//
// cm.operation(function () {
// cm.replaceRange(out, from, to);
// for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
// cm.indentLine(cur, "smart");
// cm.setSelection(from, cm.getCursor(false));
// });
// });
//})();
</pre>
</body>
</html>