3 Editor using CodeMirror
8 var codemirrorpath = "";
11 var disallowedPlatforms = ['ios', 'android', 'ipod'];
12 var default_code_mirror_options = {
13 gutters: ["note-gutter", "CodeMirror-linenumbers"],
19 tabMode: 'spaces' // or 'shift'
22 var MooShellEditor = new Class({
23 Implements: [Options, Events],
29 codeMirrorOptions: default_code_mirror_options,
30 syntaxHighlighting: []
34 'javascript': 'JavaScript',
38 'coffeescript': 'CoffeeScript',
39 'javascript 1.7': 'JavaScript 1.7'
42 initialize: function(el, options) {
43 this.validationTooltip;
45 // switch off CodeMirror for IE
46 //if (Browser.Engine.trident) options.useCodeMirror = false;
47 this.element = $(el)[0]; // jordan added [0] for jquery
48 if (!this.options.syntaxHighlighting.contains(options.language)) {
49 this.forceDefaultCodeMirrorOptions();
51 this.setOptions(options);
52 var is_disallowed = (disallowedPlatforms.contains(Browser.Platform.name));
53 if (this.options.useCodeMirror && !is_disallowed) {
57 if (!this.options.codeMirrorOptions.stylesheet && this.options.stylesheet) {
58 this.options.codeMirrorOptions.stylesheet = this.options.stylesheet.map(function(path) {
59 return mediapath + path;
62 if (!this.options.codeMirrorOptions.path) {
63 this.options.codeMirrorOptions.path = codemirrorpath + 'js/';
65 if (!this.options.codeMirrorOptions.content) {
66 this.options.codeMirrorOptions.content = this.element.get('value');
69 var parentNode = this.element.getParent();
70 var options = { value: this.element.value };
71 options = Object.append(options, this.options.codeMirrorOptions);
72 this.editor = CodeMirror(parentNode, options);
74 // run this after initialization
75 if (!this.options.codeMirrorOptions.initCallback){
76 if (this.options.codeMirrorOptions.autofocus) {
78 Layout.current_editor = this.options.name;
82 // set editor options that can only be set once the editor is initialized
83 var cur = this.editor.getLineHandle(this.editor.getCursor().line);
84 this.setEditorEvents({
86 Layout.current_editor = this.options.name;
87 // this.editor.removeLineClass(cur, 'background', 'activeline');
88 // this.editor.hlLine = this.editor.addLineClass(0, "background", "activeline");
90 cursorActivity: function(){
91 // var cur = this.editor.getLineHandle(this.editor.getCursor().line);
92 // if (cur != this.editor.hlLine) {
93 // this.editor.removeLineClass(this.editor.hlLine, 'background', 'activeline');
94 // this.editor.hlLine = this.editor.addLineClass(cur, 'background', 'activeline');
98 // this.editor.removeLineClass(this.editor.hlLine, 'background', 'activeline');
101 this.validateEditorInput.call(this, parentNode);
102 window.editorsModified = true;
106 // disable new line insertion when saving fiddle
107 CodeMirror.keyMap.default['Ctrl-Enter'] = function(){
111 // don't let Emmet capture this
112 delete CodeMirror.keyMap.default['Cmd-L'];
115 this.editorLabelFX = new Fx.Tween(this.getLabel(), {
120 this.getWindow().addEvents({
121 mouseenter: function() {
122 this.editorLabelFX.start(0);
124 mouseleave: function() {
125 this.editorLabelFX.start(0.8);
130 // mooshell.addEvents({
131 // 'run': this.b64decode.bind(this)
134 Layout.registerEditor(this);
135 this.setLabelName(this.options.language || this.options.name);
138 validateEditorInput: function(parentNode){
139 var currentValue = this.getCode();
142 // destroy tooltip if it already exists for this editor
143 if (this.validationTooltip){
144 this.validationTooltip.destroy();
147 // create the container
148 this.validationTooltip = Element('ul', {
149 'class': 'warningTooltip'
153 Object.each(this.options.disallowed, function(value, key){
154 if (currentValue.test(key, 'i')){
155 warnings.push('<li>' + value + '</li>');
160 this.validationTooltip = this.validationTooltip.inject(parentNode);
162 // squash and apply warnings
163 this.validationTooltip.set({
164 html: warnings.join('')
168 getEditor: function() {
169 return this.editor || this.element;
172 getWindow: function() {
174 this.window = this.element.getParent('.window');
179 getLabel: function() {
180 return this.getWindow().getElement('.window_label');
183 b64decode: function() {
184 this.element.set('value', this.before_decode);
187 getCode: function() {
188 return (this.editor) ? this.editor.getValue() : this.element.get('value');
191 updateFromMirror: function() {
192 this.before_decode = this.getCode();
193 this.element.set('value', Base64.encode(this.before_decode));
196 updateCode: function() {
197 this.element.set('value', this.getCode());
201 this.element.set('value', '');
205 cleanEditor: function() {
206 if (this.editor) this.editor.setCode('');
210 this.getWindow().hide();
214 this.getWindow().show();
217 setEditorOptions: function(options){
218 Object.each(options, function(fn, key){
219 this.editor.setOption(key, fn.bind(this));
223 setEditorEvents: function(e){
224 Object.each(e, function(fn, key){
225 this.editor.on(key, fn.bind(this));
229 setLanguage: function(language) {
230 // Todo: This is hacky
231 this.setLabelName(language);
234 setLabelName: function(language) {
235 this.getLabel().set('text', this.window_names[language] || language);
238 setStyle: function(key, value) {
239 if (this.editor) return $(this.editor.frame).setStyle(key, value);
240 return this.element.setStyle(key, value);
243 setStyles: function(options) {
244 if (this.editor) return $(this.editor.frame).setStyles(options);
245 return this.element.setStyles(options);
248 setWidth: function(width) {
249 this.getWindow().setStyle('width', width);
252 setHeight: function(height) {
253 this.getWindow().setStyle('height', height);
256 getPosition: function() {
257 if (this.editor) return $(this.editor.frame).getPosition();
258 return this.element.getPosition();
261 forceDefaultCodeMirrorOptions: function() {
262 this.options.codeMirrorOptions = default_code_mirror_options;
268 * JS specific settings
270 MooShellEditor.JS = new Class({
271 Extends: MooShellEditor,
275 language: 'javascript',
281 syntaxHighlighting: ['javascript', 'javascript 1.7'],
283 '<script': "Input plain JavaScript code, no HTML.",
284 'document.write': "<code>document.write</code> is disallowed in JSFiddle envioriment and might break your fiddle."
288 initialize: function(el, options) {
289 this.setOptions(options);
290 this.parent(el, this.options);
295 * CSS specific settings
297 MooShellEditor.CSS = new Class({
298 Extends: MooShellEditor,
307 syntaxHighlighting: ['css', 'scss']
310 initialize: function(el, options) {
311 this.setOptions(options);
312 this.parent(el, this.options);
317 * HTML specific settings
319 MooShellEditor.HTML = new Class({
320 Extends: MooShellEditor,
329 syntaxHighlighting: ['html'],
331 '<html': "No need for the <code>HTML</code> tag, it's already in the output.",
332 '<meta': "No need for the <code>META</code> tags.",
333 '<head*.?>': "No need for the <code>HEAD</code> tag, it's already in the output.",
334 '<doctype': "Select <code>DOCTYPE</code> from the <strong>Info</strong> panel on the left, instead of adding a tag.",
335 '<script/?.*text\/javascript': "For JavaScript use the panel below or the <strong>Resources</strong> panel for external files.",
336 '<link/?.*rel/?.*stylesheet': "For external CSS files use the <strong>Resources</strong> panel on the left.",
337 '<style': "For CSS use the panel on the right.",
341 initialize: function(el, options) {
342 this.setOptions(options);
343 this.parent(el, this.options);