Commits

Anonymous committed a07d00a

Added minimal editor in textarea. So now tab, enter key work as
expected.

Comments (0)

Files changed (6)

build/friendpaste.yml

         - src/ajax.js
     friendpaste.js:
         - src/resizeable.js
+        - src/editor.js
         - src/friendpaste.js
         - src/diff.js 

static/js/src/base.js

     return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))) };
 }
 
+function calculeOffset(element,attr){
+    var offset=0;
+    while(element){
+        offset+=element[attr];
+        element=element.offsetParent
+    }
+    return offset;
+};
+
 function resizeBottom() {
     height = 0;
     if (window.innerHeight) {

static/js/src/editor.js

+/*
+  Copyright 2008 by Benoît Chesneau <benoitc@e-engura.com>
+  Copyright 2008, Christophe Dolivet
+  
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+
+*/
+
+var Editor = base2.Base.extend({
+
+    tab_spacing: true,
+
+    constructor: function(stextarea) {
+        this.el = document.querySelector(stextarea);
+        
+        this.lastSelection = {}; 
+        this.lineHeight = 16;
+        this.tab_nb_char= 4;	//nb of white spaces corresponding to a tabulation
+        if (base2.detect("webkit"))
+            this.tab_nb_char += 1;
+
+        if (this.tab_spacing) {
+            this.tabulation =  "";
+            for(var i=0; i<this.tab_nb_char; i++)
+                this.tabulation += " ";
+        } else {
+            this.tabulation = "\t";
+        }
+        this._tab_detected = false;
+
+        // init textarea for ie
+        if (base2.detect("MSIE")) 
+            this.el.selectionStart = this.el.selectionEnd = 0;
+
+
+        this.el.addEventListener("keydown", this.handleKey.bindAsEventListener(this), false);
+    
+    
+    },
+
+    handleKey: function(e) {
+        c = e.keyCode;
+        if (c == 9) {
+            e.preventDefault();
+            this.tab_selection();
+            return false;
+        } else if (c == 13) {
+            if (this.do_enter())
+                e.preventDefault();
+            return false;
+        }
+
+        return true;
+    },
+
+    tab_selection: function() {
+        if (this._is_tabbing)
+            return
+        this._is_tabbing = true;
+
+        if (base2.detect("MSIE"))
+            this._getIESelection();
+
+        if (!this._tab_detected)
+            this._detect_tab(); 
+
+        var start = this.el.selectionStart;
+        var end = this.el.selectionEnd;
+        var insText = this.el.value.substring(start, end);
+        var pos_start=start;
+		var pos_end=end;
+		if (insText.length == 0) {
+			// if only one line selected
+			this.el.value = this.el.value.substr(0, start) + 
+                this.tabulation + this.el.value.substr(end);
+			pos_start = start + this.tabulation.length;
+			pos_end=pos_start;
+		} else {
+			start= Math.max(0, this.el.value.substr(0, start).lastIndexOf("\n")+1);
+			endText=this.el.value.substr(end);
+			startText=this.el.value.substr(0, start);
+			tmp= this.el.value.substring(start, end).split("\n");
+			insText= this.tabulation+tmp.join("\n"+this.tabulation);
+			this.el.value = startText + insText + endText;
+			pos_start = start;
+			pos_end= this.el.value.indexOf("\n", startText.length + insText.length);
+			if(pos_end==-1)
+				pos_end=this.el.value.length;
+		}
+		this.el.selectionStart = pos_start;
+		this.el.selectionEnd = pos_end;
+
+        if (base2.detect("MSIE")) {
+            this._setIESelection
+            setTimeout('this._is_tabbing=false;', 100);
+        } else {
+            this._is_tabbing = false;
+        }
+    },
+
+    do_enter: function() {
+        if (base2.detect("MSIE"))
+            this._getIESelection();
+
+        var start=this.el.selectionStart;
+		var end= this.el.selectionEnd;
+		var start_last_line= Math.max(0, 
+                this.el.value.substring(0, start).lastIndexOf("\n") + 1 );
+       
+        var latest_line = this.el.value.substring(start_last_line,
+                start)
+
+        if (latest_line.match(/^[ \t]+$/mg,""))
+            return false;
+
+        if (latest_line.replace(" \n", "").length == 0)
+            return false;
+
+        var begin_line= latest_line.replace(/^([ \t]*).*/gm, "$1");
+		if (begin_line == "\n" || begin_line == "\r" || begin_line.length == 0) 
+			return false;
+       
+         
+
+        if (base2.detect("MSIE") || base2.detect("opera")) {
+            begin_line = "\r\n" + begin_line;
+        } else {
+            begin_line = "\n" + begin_line;
+        }
+        this.el.value= this.el.value.substring(0, start) +
+            begin_line + this.el.value.substring(end);
+        this.area_select(start + begin_line.length, 0);
+        return true;
+    },
+
+    area_select: function(start, length){
+		this.el.focus();
+		
+		start = Math.max(0, Math.min(this.el.value.length, start));
+		end = Math.max(start, Math.min(this.el.value.length, start+length));
+
+		if (base2.detect("MSIE")) {
+			this.el.selectionStart = start;
+			this.el.selectionEnd = end;		
+			this._setIESelection();
+		} else {
+			if (base2.detect("opera")) {
+                this.el.setSelectionRange(0, 0);
+			}
+			this.el.setSelectionRange(start, end);
+		}
+	},
+
+    _detect_tab: function() {
+        if (this.el.value.indexOf("\t") > 0) {
+            this.tabulation = "\t";
+        } else {
+            this.tabulation =  "";
+            for(var i=0; i<this.tab_nb_char; i++)
+                this.tabulation += " ";
+        }
+        this._tab_detected = true;
+    },
+
+    _getIESelection: function() {
+        var range = document.selection.createRange();
+		var stored_range = range.duplicate();
+		stored_range.moveToElementText( this.el );
+		stored_range.setEndPoint( 'EndToEnd', range );
+		if(stored_range.parentElement() !=this.el)
+			return;
+	
+		// the range don't take care of empty lines in the end of the selection
+		var scrollTop= document.body.scrollTop;
+		
+		var relative_top = range.offsetTop - 
+            calculeOffset(this.el, "offsetTop");
+		
+		var line_start = Math.round((relative_top / this.lineHeight) +1);
+		
+		var line_nb=Math.round(range.boundingHeight / this.lineHeight);
+					
+		var range_start=stored_range.text.length - range.text.length;
+		var tab=this.el.value.substr(0, range_start).split("\n");			
+		range_start += (line_start - tab.length)*2;		// add missing empty lines to the selection
+		this.el.selectionStart = range_start;
+		
+		var range_end=this.el.selectionStart + range.text.length;
+		tab=this.el.value.substr(0, range_start + range.text.length).split("\n");			
+		range_end+= (line_start + line_nb - 1 - tab.length)*2;
+		
+		this.el.selectionEnd = range_end;
+        this.el.focus();
+    },
+
+    _setIESelection: function() {
+		var nbLineStart=this.el.value.substr(0, this.el.selectionStart).split("\n").length - 1;
+		var nbLineEnd=this.el.value.substr(0, this.el.selectionEnd).split("\n").length - 1;
+		var range = document.selection.createRange();
+		range.moveToElementText( this.el );
+		range.setEndPoint( 'EndToStart', range );
+		
+		range.moveStart('character', this.el.selectionStart - nbLineStart);
+		range.moveEnd('character', this.el.selectionEnd - nbLineEnd - (this.el.selectionStart - nbLineStart)  );
+		range.select();
+	}
+
+});

static/js/src/friendpaste.js

         if(!base2.detect("webkit"))
             new Resizeable("#paste_snippet");
 
+        new Editor("#paste_snippet");
+
         this.setSettings();
         
         document.querySelector("#change-theme").addEventListener("change", 

templates/paste/index.html

 {% if DEBUG %}
 <script type="text/javascript" src="/static/js/src/resizeable.js"></script>
 <script type="text/javascript" src="/static/js/src/friendpaste.js"></script>
+<script type="text/javascript" src="/static/js/src/editor.js"></script>
+
 {% else %}
 <script type="text/javascript" src="/static/js/friendpaste.js?20081122"></script>
 {% endif %}
 
 <script type="text/javascript">
     if(!base2.detect("webkit"))
-            new Resizeable("#paste_snippet");
+        new Resizeable("#paste_snippet");
+
+    // init source code editor
+    new Editor("#paste_snippet");
+
     document.querySelector("#paste_snippet").focus();
 </script>
 {% endblock %}

templates/paste/view.html

 {% block script %}
 {% if DEBUG %}
 <script type="text/javascript" src="/static/js/src/resizeable.js"></script>
+<script type="text/javascript" src="/static/js/src/editor.js"></script>
 <script type="text/javascript" src="/static/js/src/friendpaste.js"></script>
 {% else %}
 <script type="text/javascript" src="/static/js/friendpaste.js?20081122"></script>