move a few things away in to-be-integrated/
[myslice.git] / to-be-integrated / plugins / code_editor / static / js / code_editor.js
diff --git a/to-be-integrated/plugins/code_editor/static/js/code_editor.js b/to-be-integrated/plugins/code_editor/static/js/code_editor.js
new file mode 100644 (file)
index 0000000..664bbdc
--- /dev/null
@@ -0,0 +1,433 @@
+/**
+ * Description: CodeEditor plugin
+ * Copyright (c) 2012 UPMC Sorbonne Universite - INRIA
+ * License: GPLv3
+ */
+
+/*
+ * It's a best practice to pass jQuery to an IIFE (Immediately Invoked Function
+ * Expression) that maps it to the dollar sign so it can't be overwritten by
+ * another library in the scope of its execution.
+ */
+
+(function($){
+
+     var default_code_mirror_options = {
+       gutters: ["note-gutter", "CodeMirror-linenumbers"],
+       tabSize: 4,
+       indentUnit: 4,
+       matchBrackets: true,
+       lineNumbers: true,
+       lineWrapping: true,
+       tabMode: 'spaces' // or 'shift'
+     };
+
+    
+    // routing calls
+    jQuery.fn.CodeEditor = function( method ) {
+               if ( methods[method] ) {
+                       return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
+               } else if ( typeof method === 'object' || ! method ) {
+                       return methods.init.apply( this, arguments );
+               } else {
+                       jQuery.error( 'Method ' +  method + ' does not exist on jQuery.CodeEditor' );
+               }    
+    };
+
+    /***************************************************************************
+     * Public methods
+     ***************************************************************************/
+
+    var methods = {
+
+        /**
+         * @brief Plugin initialization
+         * @param options : an associative array of setting values
+         * @return : a jQuery collection of objects on which the plugin is
+         *     applied, which allows to maintain chainability of calls
+         */
+        init : function ( options ) {
+
+            /* Default settings */
+            var options = $.extend( {
+                useCodeMirror: true,
+                codeMirrorOptions: default_code_mirror_options,
+                syntaxHighlighting: []
+            }, options);
+
+            return this.each(function() {
+
+                var $this = $(this);
+
+                /* An object that will hold private variables and methods */
+                var plugin = new CodeEditor(options);
+                $this.data('Manifold', plugin);
+
+                /* Events */
+                $this.on('show.CodeEditor', methods.show);
+
+            }); // this.each
+        }, // init
+
+        /**
+         * @brief Plugin destruction
+         * @return : a jQuery collection of objects on which the plugin is
+         *     applied, which allows to maintain chainability of calls
+         */
+        destroy : function( ) {
+
+            return this.each(function() {
+                var $this = $(this);
+                var hazelnut = $this.data('Manifold');
+
+                // Unbind all events using namespacing
+                $(window).unbind('Manifold');
+
+                // Remove associated data
+                hazelnut.remove();
+                $this.removeData('Manifold');
+            });
+        }, // destroy
+
+        show : function( ) {
+            var $this=$(this);
+            // xxx wtf. why [1] ? would expect 0...
+            if (debug)
+                messages.debug("Hitting suspicious line in hazelnut.show");
+            var oTable = $($('.dataTable', $this)[1]).dataTable();
+            oTable.fnAdjustColumnSizing()
+
+            /* Refresh dataTabeles if click on the menu to display it : fix dataTables 1.9.x Bug */
+            $(this).each(function(i,elt) {
+                if (jQuery(elt).hasClass('dataTables')) {
+                    var myDiv=jQuery('#hazelnut-' + this.id).parent();
+                    if(myDiv.height()==0) {
+                        var oTable=$('#hazelnut-' + this.id).dataTable();
+                        oTable.fnDraw();
+                    }
+                }
+            });
+        } // show
+
+    }; // var methods;
+
+    /***************************************************************************
+     * Plugin object
+     ***************************************************************************/
+
+    function CodeEditor(options)
+    {
+      
+        this.initialize = function() {
+            this.validationTooltip;
+        
+            // switch off CodeMirror for IE
+            //if (Browser.Engine.trident) options.useCodeMirror = false;
+            this.element = $('#' + this.options.plugin_uuid + '-textarea')[0]; // jordan added [0] for jquery
+            if (!this.options.syntaxHighlighting.contains(this.options.language)) {
+                this.forceDefaultCodeMirrorOptions();
+            }
+            //this.setOptions(this.options);
+            var is_disallowed = (disallowedPlatforms.contains(Browser.Platform.name));
+            if (this.options.useCodeMirror && !is_disallowed) {
+                // hide textarea
+                this.element.hide();
+                // prepare settings
+                if (!this.options.codeMirrorOptions.stylesheet && this.options.stylesheet) {
+                    this.options.codeMirrorOptions.stylesheet = this.options.stylesheet.map(function(path) {
+                        return mediapath + path;
+                    });
+                }
+                if (!this.options.codeMirrorOptions.path) {
+                    var codemirrorpath = ''; // jordan
+                    this.options.codeMirrorOptions.path = codemirrorpath + 'js/';
+                }
+                if (!this.options.codeMirrorOptions.content) {
+                    this.options.codeMirrorOptions.content = this.element.get('value');
+                }
+          
+                var parentNode = this.element.getParent();
+                var options = { value: this.element.value };
+                options = Object.append(options, this.options.codeMirrorOptions);
+                this.editor = CodeMirror(parentNode, options);
+          
+                // run this after initialization
+                if (!this.options.codeMirrorOptions.initCallback){
+                    if (this.options.codeMirrorOptions.autofocus) {
+                        // set current editor
+                        Layout.current_editor = this.options.name;
+                    }
+                }
+          
+                // set editor options that can only be set once the editor is initialized
+                var cur = this.editor.getLineHandle(this.editor.getCursor().line);
+                this.setEditorEvents({
+                    focus: function(){
+                        Layout.current_editor = this.options.name;
+                        // this.editor.removeLineClass(cur, 'background', 'activeline');
+                        // this.editor.hlLine = this.editor.addLineClass(0, "background", "activeline");
+                    },
+                    cursorActivity: function(){
+                        // var cur = this.editor.getLineHandle(this.editor.getCursor().line);
+                        // if (cur != this.editor.hlLine) {
+                        //   this.editor.removeLineClass(this.editor.hlLine, 'background', 'activeline');
+                        //   this.editor.hlLine = this.editor.addLineClass(cur, 'background', 'activeline');
+                        // }
+                    },
+                    blur: function(){
+                        // this.editor.removeLineClass(this.editor.hlLine, 'background', 'activeline');
+                    },
+                    change: function(){
+                        this.validateEditorInput.call(this, parentNode);
+                        window.editorsModified = true;
+                    }.bind(this)
+                });
+          
+                // disable new line insertion when saving fiddle
+                CodeMirror.keyMap.default['Ctrl-Enter'] = function(){
+                    return false;
+                };
+        
+                // don't let Emmet capture this
+                delete CodeMirror.keyMap.default['Cmd-L'];
+            }
+        
+            this.editorLabelFX = new Fx.Tween(this.getLabel(), {
+                property: 'opacity',
+                link: 'cancel'
+            });
+        
+            this.getWindow().addEvents({
+                mouseenter: function() {
+                    this.editorLabelFX.start(0);
+                }.bind(this),
+                mouseleave: function() {
+                    this.editorLabelFX.start(0.8);
+                }.bind(this)
+            });
+        
+            // jordan commented
+            //    mooshell.addEvents({
+            //      'run': this.b64decode.bind(this)
+            //    });
+        
+            Layout.registerEditor(this);
+            this.setLabelName(this.options.language || this.options.name);
+        },
+      
+        /**
+         *
+         */
+        this.validateEditorInput = function(parentNode){
+            var currentValue = this.getCode();
+            var warnings = [];
+      
+            // destroy tooltip if it already exists for this editor
+            if (this.validationTooltip){
+                this.validationTooltip.destroy();
+            }
+      
+            // create the container
+            this.validationTooltip = Element('ul', {
+                'class': 'warningTooltip'
+            });
+      
+            // collect warnings
+            Object.each(this.options.disallowed, function(value, key){
+                if (currentValue.test(key, 'i')){
+                    warnings.push('<li>' + value + '</li>');
+                }
+            });
+      
+            // inject container
+            this.validationTooltip = this.validationTooltip.inject(parentNode);
+      
+            // squash and apply warnings
+            this.validationTooltip.set({
+                html: warnings.join('')
+            });
+        },
+      
+        /**
+         *
+         */
+        this.getEditor = function() {
+            return this.editor || this.element;
+        },
+      
+        /**
+         *
+         */
+        this.getWindow = function() {
+            if (!this.window) {
+                this.window = this.element.getParent('.window');
+            }
+            return this.window;
+        },
+      
+        /**
+         *
+         */
+        this.getLabel = function() {
+            return this.getWindow().getElement('.window_label');
+        },
+      
+        /**
+         *
+         */
+        this.b64decode = function() {
+            this.element.set('value', this.before_decode);
+        },
+      
+        /**
+         *
+         */
+        this.getCode = function() {
+            return (this.editor) ? this.editor.getValue() : this.element.get('value');
+        },
+      
+        /**
+         *
+         */
+        this.updateFromMirror = function() {
+            this.before_decode = this.getCode();
+            this.element.set('value', Base64.encode(this.before_decode));
+        },
+      
+        /**
+         *
+         */
+        this.updateCode = function() {
+            this.element.set('value', this.getCode());
+        },
+      
+        /**
+         *
+         */
+        this.clean = function() {
+            this.element.set('value', '');
+            this.cleanEditor();
+        },
+      
+        /**
+         *
+         */
+        this.cleanEditor = function() {
+            if (this.editor) this.editor.setCode('');
+        },
+      
+        /**
+         *
+         */
+        this.hide = function() {
+            this.getWindow().hide();
+        },
+      
+        this.show = function() {
+            this.getWindow().show();
+        },
+      
+        /**
+         *
+         */
+        this.setEditorOptions = function(options){
+            Object.each(options, function(fn, key){
+                this.editor.setOption(key, fn.bind(this));
+            }, this);
+        },
+      
+        /**
+         *
+         */
+        this.setEditorEvents = function(e){
+            Object.each(e, function(fn, key){
+                this.editor.on(key, fn.bind(this));
+            }, this);
+        },
+      
+        /**
+         *
+         */
+        this.setLanguage = function(language) {
+            // Todo: This is hacky
+            this.setLabelName(language);
+        },
+      
+        /**
+         *
+         */
+        this.setLabelName = function(language) {
+            this.getLabel().set('text', this.window_names[language] || language);
+        },
+      
+        /**
+         *
+         */
+        this.setStyle = function(key, value) {
+            if (this.editor) return $(this.editor.frame).setStyle(key, value);
+            return this.element.setStyle(key, value);
+        },
+      
+        /**
+         *
+         */
+        this.setStyles = function(options) {
+            if (this.editor) return $(this.editor.frame).setStyles(options);
+            return this.element.setStyles(options);
+        },
+      
+        /**
+         *
+         */
+        this.setWidth = function(width) {
+            this.getWindow().setStyle('width', width);
+        },
+      
+        /**
+         *
+         */
+        this.setHeight = function(height) {
+            this.getWindow().setStyle('height', height);
+        },
+      
+        /**
+         *
+         */
+        this.getPosition = function() {
+            if (this.editor) return $(this.editor.frame).getPosition();
+            return this.element.getPosition();
+        },
+      
+        /**
+         *
+         */
+        this.forceDefaultCodeMirrorOptions = function() {
+            this.options.codeMirrorOptions = default_code_mirror_options;
+        }
+
+        // BEGIN CONSTRUCTOR
+
+        /* member variables */
+        this.options = options;
+
+        var object = this;
+
+        // adapted from EditorCM.js from jsfiddle.net
+
+        var disallowedPlatforms = ['ios', 'android', 'ipod'];
+
+        this.window_names = {
+          'javascript': 'JavaScript',
+          'html': 'HTML',
+          'css': 'CSS',
+          'scss': 'SCSS',
+          'coffeescript': 'CoffeeScript',
+          'javascript 1.7': 'JavaScript 1.7'
+        };
+
+        this.initialize();
+        // END CONSTRUCTOR
+    } // function CodeEditor
+
+})( jQuery );
+