Skip to content

Commit

Permalink
First iteration of a chunky bacon editor in the tippytippytepee
Browse files Browse the repository at this point in the history
  • Loading branch information
lwu committed Jan 30, 2007
1 parent f2503a7 commit 68ed183
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 13 deletions.
5 changes: 5 additions & 0 deletions examples/tippytippytepee/static/codepress.css
@@ -0,0 +1,5 @@
html {border:none;} /*remove ie frameborder */
body {margin-top:13px;_margin-top:14px;background:white;font-family:monospace;font-size:13px;margin-left:32px;white-space:pre;background-image:url("/static/linenumbers.png");background-repeat:repeat-y;background-position:0 3px;line-height:16px;}
html>body{background-position:0 2px;}
P {margin:0;padding:0;border:0;outline:0;display:block;white-space:pre;}
b, i, s, u, a, em, tt, ins, big, cite, strong {text-decoration:none;font-weight:normal;font-style:normal;font-size:13px;}
240 changes: 240 additions & 0 deletions examples/tippytippytepee/static/codepress.js
@@ -0,0 +1,240 @@
/*
* CodePress - Real Time Syntax Highlighting Editor written in JavaScript - http://codepress.fermads.net/
*
* Copyright (C) 2006 Fernando M.A.d.S. <fermads@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation.
*
* Read the full licence: http://www.opensource.org/licenses/lgpl-license.php
*
* This is a slightly modified copy of version 0.8.15 (13 january 2007).
* A few lines here and in the CSS were modified to use 'static' as a prefix.
*/

CodePress = {
range : null,
language : null,
scrolling : false,

// set initial vars and start sh
initialize : function() {
if(typeof(editor)=='undefined'&&!arguments[0]) return;
this.detect();
chars = '|13|32|191|57|48|187|188|'; // charcodes that trigger syntax highlighting
cc = '\u2009'; // control char
if(browser.ff) {
editor = document.getElementById('ffedt');
document.designMode = 'on';
document.addEventListener('keydown', this.keyHandler, true);
window.addEventListener('scroll', function() { if(!CodePress.scrolling) CodePress.syntaxHighlight('scroll') }, false);
}
else if(browser.ie) {
editor = document.getElementById('ieedt');
editor.contentEditable = 'true';
document.attachEvent('onkeydown', this.keyHandler);
window.attachEvent('onscroll', function() { if(!CodePress.scrolling) CodePress.syntaxHighlight('scroll') });
}
else {
// TODO: textarea without syntax highlighting for non supported browsers
alert('your browser is not supported at the moment');
return;
}
this.syntaxHighlight('init');
setTimeout(function() { window.scroll(0,0) },50); // scroll IE to top
},

// detect browser, for now IE and FF
detect : function() {
browser = { ie:false, ff:false };
if(navigator.appName.indexOf("Microsoft") != -1) browser.ie = true;
else if(navigator.appName == "Netscape") browser.ff = true;
},

// treat key bindings
keyHandler : function(evt) {
evt = (evt) ? evt : (window.event) ? event : null;
if(evt) {
charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode : ((evt.which) ? evt.which : 0));

if((charCode==34||charCode==33)&&browser.ie) { // handle page up/down for IE
parent.codepress.scrollBy(0, (charCode==34) ? 200 : -200);
evt.returnValue = false;
}
if((chars.indexOf('|'+charCode+'|')!=-1) && (!evt.ctrlKey && !evt.altKey)) { // syntax highlighting
CodePress.syntaxHighlight('generic');
}
else if(charCode==46||charCode==8) { // save to history when delete or backspace pressed
CodePress.actions.history[CodePress.actions.next()] = editor.innerHTML;
}
else if((charCode==90||charCode==89) && evt.ctrlKey) { // undo and redo
(charCode==89||evt.shiftKey) ? CodePress.actions.redo() : CodePress.actions.undo() ;
evt.returnValue = false;
if(browser.ff)evt.preventDefault();
}
else if(charCode==86 && evt.ctrlKey) { // paste
// TODO: pasted text should be parsed and highlighted
}

}
},

// put cursor back to its original position after every parsing
findString : function() {
if(browser.ff) {
if(self.find(cc))
window.getSelection().getRangeAt(0).deleteContents();
}
else if(browser.ie) {
range = self.document.body.createTextRange();
if(range.findText(cc)){
range.select();
range.text = '';
}
}
},

// split big files, highlighting parts of it
split : function(code,flag) {
if(flag=='scroll') {
this.scrolling = true;
return code;
}
else {
this.scrolling = false;
mid = code.indexOf(cc);
if(mid-2000<0) {ini=0;end=4000;}
else if(mid+2000>code.length) {ini=code.length-4000;end=code.length;}
else {ini=mid-2000;end=mid+2000;}
code = code.substring(ini,end);
if(browser.ff) return code;
else return code.substring(code.indexOf('<P>'),code.lastIndexOf('</P>')+4);
}
},

// syntax highlighting parser
syntaxHighlight : function(flag) {
if(browser.ff) {
if(flag!='init') window.getSelection().getRangeAt(0).insertNode(document.createTextNode(cc));
o = editor.innerHTML;
o = o.replace(/<br>/g,'\n');
o = o.replace(/<.*?>/g,'');
x = z = this.split(o,flag);
x = x.replace(/\n/g,'<br>');
}
else if(browser.ie) {
if(flag!='init') document.selection.createRange().text = cc;
o = editor.innerHTML;
o = o.replace(/<P>/g,'\n');
o = o.replace(/<\/P>/g,'\r');
o = o.replace(/<.*?>/g,'');
o = o.replace(/&nbsp;/g,'');
o = '<PRE><P>'+o+'</P></PRE>';
o = o.replace(/\n/g,'<P>');
o = o.replace(/\r/g,'<\/P>');
o = o.replace(/<P>(<P>)+/,'<P>');
o = o.replace(/<\/P>(<\/P>)+/,'</P>');
o = o.replace(/<P><\/P>/g,'<P><BR /><\/P>');
x = z = this.split(o,flag);
}

for(i=0;i<syntax.length;i+=2)
x = x.replace(syntax[i],syntax[i+1]);

editor.innerHTML = this.actions.history[this.actions.next()] = (flag=='scroll') ? x : o.replace(z,x);

if(flag!='init') this.findString();
},

// undo and redo methods
actions : {
pos : -1, // actual history position
history : [], // history vector

undo : function() {
if(editor.innerHTML.indexOf(cc)==-1){
if(browser.ff) window.getSelection().getRangeAt(0).insertNode(document.createTextNode(cc));
else document.selection.createRange().text = cc;
this.history[this.pos] = editor.innerHTML;
}
this.pos--;
if(typeof(this.history[this.pos])=='undefined') this.pos++;
editor.innerHTML = this.history[this.pos];
CodePress.findString();
},

redo : function() {
this.pos++;
if(typeof(this.history[this.pos])=='undefined') this.pos--;
editor.innerHTML = this.history[this.pos];
CodePress.findString();
},

next : function() { // get next vector position and clean old ones
if(this.pos>20) this.history[this.pos-21] = undefined;
return ++this.pos;
}
},

// transform syntax highlighted code to original code
getCode : function() {
code = editor.innerHTML;
code = code.replace(/<br>/g,'\n');
code = code.replace(/<\/p>/gi,'\r');
code = code.replace(/<p>/i,''); // IE first line fix
code = code.replace(/<p>/gi,'\n');
code = code.replace(/&nbsp;/gi,'');
code = code.replace(/\u2009/g,'');
code = code.replace(/<.*?>/g,'');
code = code.replace(/&lt;/g,'<');
code = code.replace(/&gt;/g,'>');
code = code.replace(/&amp;/gi,'&');
return code;
},

// put some code inside editor
setCode : function() {
if(typeof(arguments[1])=='undefined') {
language = top.document.getElementById(arguments[0]).lang.toLowerCase();
code = top.document.getElementById(arguments[0]).value;
}
else {
language = arguments[0];
code = arguments[1];
}
document.designMode = 'off';
head = document.getElementsByTagName('head')[0];
script = document.createElement('script');
script.type = 'text/javascript';
script.src = '/static/languages/codepress-'+language+'.js';
head.appendChild(script)
document.getElementById('cp-lang-style').href = '/static/languages/codepress-'+language+'.css';
code = code.replace(/\u2009/gi,'');
code = code.replace(/&/gi,'&amp;');
code = code.replace(/</g,'&lt;');
code = code.replace(/>/g,'&gt;');
editor.innerHTML = "<pre>"+code+"</pre>";
this.language = language;
}
}

onload = function() {
cpWindow = top.document.getElementById('codepress');
if(cpWindow!=null) {
cpWindow.style.border = '1px solid gray';
cpWindow.style.frameBorder = '0';
}

top.CodePress = CodePress;
CodePress.initialize('new');

cpOnload = top.document.getElementById('codepress-onload');
cpOndemand = top.document.getElementById('codepress-ondemand');

if(cpOnload!=null) {
cpOnload.style.display = 'none';
cpOnload.id = 'codepress-loaded';
CodePress.setCode('codepress-loaded');
}
if(cpOndemand!=null) cpOndemand.style.display = 'none';
}
10 changes: 10 additions & 0 deletions examples/tippytippytepee/static/languages/codepress-ruby.css
@@ -0,0 +1,10 @@
/*
* CodePress color styles for Ruby syntax highlighting
*/

b {color:#7F0055;font-weight:bold;} /* reserved words */
i, i b, i s, i em, i a, i u {color:gray;font-weight:normal;} /* comments */
s, s b, s a, s em, s u {color:#2A00FF;font-weight:normal;} /* strings */
a {color:#006700;font-weight:bold;} /* variables */
em {color:darkblue;font-weight:bold;} /* functions */
u {font-weight:bold;} /* special chars */
16 changes: 16 additions & 0 deletions examples/tippytippytepee/static/languages/codepress-ruby.js
@@ -0,0 +1,16 @@
/*
* CodePress regular expressions for Ruby syntax highlighting
*/

syntax = [ // Ruby
/\"(.*?)(\"|<br>|<\/P>)/g,'<s>"$1$2</s>', // strings double quote
/\'(.*?)(\'|<br>|<\/P>)/g,'<s>\'$1$2</s>', // strings single quote
/([\$\@\%]+)([\w\.]*)/g,'<a>$1$2</a>', // vars
/(def\s+)([\w\.]*)/g,'$1<em>$2</em>', // functions
/\b(alias|and|BEGIN|begin|break|case|class|def|defined|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield)\b/g,'<b>$1</b>', // reserved words
/([\(\){}])/g,'<u>$1</u>', // special chars
/#(.*?)(<br>|<\/P>)/g,'<i>#$1</i>$2', // comments
];

CodePress.initialize();

Binary file added examples/tippytippytepee/static/linenumbers.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 59 additions & 12 deletions examples/tippytippytepee/tepee.rb
Expand Up @@ -115,8 +115,30 @@ def get

class Stylesheet < R '/css/tepee.css'
def get
@headers['Content-Type'] = 'text/css'
File.read(__FILE__).gsub(/.*__END__/m, '')
@headers['Content-Type'] = 'text/css'
File.read(__FILE__).gsub(/.*__END__/m, '')
end
end

class Editor < R '/chunky/bacon/editor'
def get
@no_layout = true
render :edit_code
end
end

class Static < R '(/static/.+)'
MIME_TYPES = {'.css' => 'text/css', '.js' => 'text/javascript',
'.jpg' => 'image/jpeg', '.png' => 'image/png'}
PATH = File.expand_path('.')

def get(path)
@headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
if path.include? '..' || Path.expand_path(PATH+path) !~ /^#{PATH}/
"404 - Invalid path"
else
@headers['X-Sendfile'] = PATH+path
end
end
end
end
Expand All @@ -132,12 +154,12 @@ def layout
style <<-END, :type => 'text/css'
body {
font-family: verdana, arial, sans-serif;
min-width: 800px;
min-width: 900px;
background:#d7d7d7;
text-align: center;
}
#doc {
width: 800px;
width: 900px;
background:#ffffff;
margin-left: auto;
margin-right: auto;
Expand Down Expand Up @@ -217,16 +239,38 @@ def show
def edit
h1 @page.title
form :method => 'post', :action => R(Edit, @page.title) do
input :type => 'submit', :value=>'save'
input :type => 'submit', :value=>'save', :onclick=>'copyCode()'
p do
textarea @page.body, :name => 'post_body', :rows => 30, :cols => 100
iframe :id=>'codepress', :name=>'codepress', :src=>'/chunky/bacon/editor', :width=>850, :height=>400
br
textarea @page.body, :id=>'codepress-onload', :name => 'post_body', :lang=>'ruby'
end
input :type => 'submit', :value=>'save'
script 'function copyCode() {
var txt = document.getElementsByName("post_body")[0];
txt.value = CodePress.getCode(); } ', :type => 'text/javascript'
input :type => 'submit', :value=>'save', :onclick=>'copyCode()'
end
_button 'cancel', R(Show, @page.title, @page.version)
a 'syntax', :href => 'http://pub.cozmixng.org/~the-rwiki/?cmd=view;name=ERbMemo.en', :target=>'_blank'
end

def edit_code
html do
head do
link :href=>'/static/codepress.css', :rel=>'stylesheet', :type=>'text/css'
link :href=>'/static/languages/codepress-ruby.css', :rel=>'stylesheet',
:type=>'text/css', :id=>'cp-lang-style'
script :type=>'text/javascript', :src=>'/static/codepress.js'
script :type=>'text/javascript', :src=>'/static/languages/codepress-ruby.js'
script "CodePress.language = 'ruby';", :type=>'text/javascript'
end
body :id=>'ffedt' do
pre :id=>'ieedt' do
end
end
end
end

def list
h1 'all pages'
ul { @pages.each { |p|
Expand Down Expand Up @@ -306,12 +350,15 @@ def Tepee.create
Tepee::Models::Session.create_schema
end

require 'mongrel/camping'
Tepee::Models::Base.establish_connection :adapter => 'sqlite3', :database => ENV['HOME'] + '/.camping.db'
Tepee::Models::Base.threaded_connections=false
if __FILE__ == $0
require 'mongrel/camping'
Tepee::Models::Base.establish_connection :adapter => 'sqlite3', :database => ENV['HOME'] + '/.camping.db'
Tepee::Models::Base.logger = Logger.new('tepee.log')
Tepee::Models::Base.threaded_connections=false

s = Mongrel::Camping.start('0.0.0.0', 3300, '/', Tepee)
s.run.join
s = Mongrel::Camping.start('0.0.0.0', 3300, '/', Tepee)
s.run.join
end

__END__
/** focus **/
Expand Down
3 changes: 2 additions & 1 deletion examples/tippytippytepee/webdev.rb
Expand Up @@ -13,6 +13,7 @@ def self.get_code(uri)
end

def self.import(wiki_node)
eval self.get_code(wiki_node.to_s)
src = self.get_code(wiki_node.to_s)
eval src
end
end

0 comments on commit 68ed183

Please sign in to comment.