Initial commit
This commit is contained in:
commit
4c6a5bd129
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.sqlite3
|
||||
*.rbc
|
||||
public/system/*
|
13
Gemfile
Normal file
13
Gemfile
Normal file
@ -0,0 +1,13 @@
|
||||
source :rubygems
|
||||
|
||||
gem 'bundler'
|
||||
gem 'sinatra'
|
||||
gem 'dm-core'
|
||||
gem 'dm-timestamps'
|
||||
gem 'dm-migrations'
|
||||
gem 'dm-validations'
|
||||
gem 'dm-serializer'
|
||||
gem 'dm-sqlite-adapter'
|
||||
gem 'dm-postgres-adapter'
|
||||
gem "dm-paperclip"
|
||||
gem 'require_relative'
|
85
Gemfile.lock
Normal file
85
Gemfile.lock
Normal file
@ -0,0 +1,85 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
addressable (2.2.4)
|
||||
data_objects (0.10.3)
|
||||
addressable (~> 2.1)
|
||||
datamapper (1.0.2)
|
||||
dm-aggregates (= 1.0.2)
|
||||
dm-constraints (= 1.0.2)
|
||||
dm-core (= 1.0.2)
|
||||
dm-migrations (= 1.0.2)
|
||||
dm-serializer (= 1.0.2)
|
||||
dm-timestamps (= 1.0.2)
|
||||
dm-transactions (= 1.0.2)
|
||||
dm-types (= 1.0.2)
|
||||
dm-validations (= 1.0.2)
|
||||
dm-aggregates (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
dm-constraints (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
dm-migrations (~> 1.0.2)
|
||||
dm-core (1.0.2)
|
||||
addressable (~> 2.2)
|
||||
extlib (~> 0.9.15)
|
||||
dm-do-adapter (1.0.2)
|
||||
data_objects (~> 0.10.2)
|
||||
dm-core (~> 1.0.2)
|
||||
dm-migrations (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
dm-paperclip (2.4.1)
|
||||
datamapper
|
||||
extlib
|
||||
dm-postgres-adapter (1.0.2)
|
||||
dm-do-adapter (~> 1.0.2)
|
||||
do_postgres (~> 0.10.2)
|
||||
dm-serializer (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
fastercsv (~> 1.5.3)
|
||||
json_pure (~> 1.4)
|
||||
dm-sqlite-adapter (1.0.2)
|
||||
dm-do-adapter (~> 1.0.2)
|
||||
do_sqlite3 (~> 0.10.2)
|
||||
dm-timestamps (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
dm-transactions (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
dm-types (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
fastercsv (~> 1.5.3)
|
||||
json_pure (~> 1.4)
|
||||
stringex (~> 1.1.0)
|
||||
uuidtools (~> 2.1.1)
|
||||
dm-validations (1.0.2)
|
||||
dm-core (~> 1.0.2)
|
||||
do_postgres (0.10.3)
|
||||
data_objects (= 0.10.3)
|
||||
do_sqlite3 (0.10.3)
|
||||
data_objects (= 0.10.3)
|
||||
extlib (0.9.15)
|
||||
fastercsv (1.5.4)
|
||||
json_pure (1.5.1)
|
||||
rack (1.2.1)
|
||||
require_relative (0.0.1)
|
||||
sinatra (1.2.0)
|
||||
rack (~> 1.1)
|
||||
tilt (>= 1.2.2, < 2.0)
|
||||
stringex (1.1.0)
|
||||
tilt (1.2.2)
|
||||
uuidtools (2.1.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
bundler
|
||||
dm-core
|
||||
dm-migrations
|
||||
dm-paperclip
|
||||
dm-postgres-adapter
|
||||
dm-serializer
|
||||
dm-sqlite-adapter
|
||||
dm-timestamps
|
||||
dm-validations
|
||||
require_relative
|
||||
sinatra
|
68
app.rb
Normal file
68
app.rb
Normal file
@ -0,0 +1,68 @@
|
||||
APP_ROOT = File.dirname(__FILE__)
|
||||
|
||||
require_relative 'config/init'
|
||||
require_relative 'app/models'
|
||||
|
||||
set :root, File.dirname(__FILE__)
|
||||
set :static, true
|
||||
set :views, File.join(APP_ROOT, 'app', 'views')
|
||||
|
||||
helpers do
|
||||
def player_data(movie)
|
||||
data = File.read(movie.typescript.path).split("\n",2)[1]
|
||||
time = File.read(movie.timing.path)
|
||||
|
||||
chars = "'" + data.bytes.map { |b| '\x' + format('%02x', b) }.join('') + "'";
|
||||
formatted_time = '[' + time.split("\n").map { |line| delay, n = line.split; '[' + delay.to_f.to_s + ',' + n.to_i.to_s + ']'}.join(',') + ']'
|
||||
|
||||
out = "<script>\n"
|
||||
out << "var data = #{chars};\n"
|
||||
out << "var time = #{formatted_time};\n"
|
||||
out << "var cols = #{movie.terminal_cols};\n"
|
||||
out << "var lines = #{movie.terminal_lines};\n"
|
||||
out << "</script>"
|
||||
out
|
||||
end
|
||||
end
|
||||
|
||||
def make_paperclip_mash(file_hash)
|
||||
mash = Mash.new
|
||||
mash['tempfile'] = file_hash[:tempfile]
|
||||
mash['filename'] = file_hash[:filename]
|
||||
mash['content_type'] = file_hash[:type]
|
||||
mash['size'] = file_hash[:tempfile].size
|
||||
mash
|
||||
end
|
||||
|
||||
get %r{/(?<id>\d+)} do
|
||||
@movie = Movie.get(params[:id]) or pass
|
||||
erb :show
|
||||
end
|
||||
|
||||
get '/' do
|
||||
@movies = Movie.all(:order => :created_at.desc)
|
||||
erb :index
|
||||
end
|
||||
|
||||
get '/about' do
|
||||
erb :about
|
||||
end
|
||||
|
||||
post '/scripts' do
|
||||
movie = Movie.new(
|
||||
:terminal_cols => params[:terminal_cols],
|
||||
:terminal_lines => params[:terminal_lines],
|
||||
:typescript => make_paperclip_mash(params[:typescript]),
|
||||
:timing => make_paperclip_mash(params[:timing])
|
||||
)
|
||||
|
||||
if movie.save
|
||||
response.status = 201
|
||||
content_type = :json
|
||||
movie.to_json
|
||||
else
|
||||
response.status = 422
|
||||
content_type = :json
|
||||
movie.errors.to_json
|
||||
end
|
||||
end
|
32
app/models.rb
Normal file
32
app/models.rb
Normal file
@ -0,0 +1,32 @@
|
||||
class Movie
|
||||
include DataMapper::Resource
|
||||
include Paperclip::Resource
|
||||
|
||||
property :id, Serial
|
||||
|
||||
property :name, String
|
||||
|
||||
property :typescript_file_name, String, :required => true, :length => 256
|
||||
property :typescript_content_type, String, :length => 128
|
||||
property :typescript_file_size, Integer
|
||||
property :typescript_updated_at, DateTime
|
||||
|
||||
property :timing_file_name, String, :required => true, :length => 256
|
||||
property :timing_content_type, String, :length => 128
|
||||
property :timing_file_size, Integer
|
||||
property :timing_updated_at, DateTime
|
||||
|
||||
property :terminal_type, String
|
||||
property :terminal_cols, Integer, :required => true
|
||||
property :terminal_lines, Integer, :required => true
|
||||
|
||||
timestamps :at
|
||||
|
||||
has_attached_file :typescript, :path => "#{APP_ROOT}/public/system/:attachment/:id"
|
||||
has_attached_file :timing, :path => "#{APP_ROOT}/public/system/:attachment/:id"
|
||||
|
||||
validates_attachment_presence :typescript
|
||||
validates_attachment_presence :timing
|
||||
end
|
||||
|
||||
DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{File.expand_path(File.join(APP_ROOT, 'db', 'db.sqlite3'))}")
|
9
app/views/index.erb
Normal file
9
app/views/index.erb
Normal file
@ -0,0 +1,9 @@
|
||||
<h2>Ansi.tv</h2>
|
||||
|
||||
<ul class="movies">
|
||||
<% @movies.each do |movie| %>
|
||||
<li class="movie">
|
||||
<a href="/<%= movie.id %>"><%= movie.id %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
31
app/views/layout.erb
Normal file
31
app/views/layout.erb
Normal file
@ -0,0 +1,31 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="/javascripts/utf8.js" type="text/javascript"></script>
|
||||
<script src="/javascripts/misc.js" type="text/javascript"></script>
|
||||
<script src="/javascripts/player.js" type="text/javascript"></script>
|
||||
<script src="/javascripts/ansi-interpreter.js" type="text/javascript"></script>
|
||||
<script src="/javascripts/terminal.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="/stylesheets/reset.css" />
|
||||
<link rel="stylesheet" href="/stylesheets/main.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="all">
|
||||
<div id="top">
|
||||
<div id="logo">
|
||||
<h1>vterm.tv</h1>
|
||||
</div>
|
||||
<div id="menu">
|
||||
<ul class="links">
|
||||
<li>Sign in</li>
|
||||
<li>Sign up</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="main">
|
||||
<%= yield %>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
16
app/views/show.erb
Normal file
16
app/views/show.erb
Normal file
@ -0,0 +1,16 @@
|
||||
<h2>Becoming more productive with Vim (<%= @movie.id %>)</h2>
|
||||
|
||||
<div class="movie">
|
||||
<div class="player">
|
||||
<pre class="term"></pre>
|
||||
<div class="hud">--------------========</div>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
|
||||
<div class="description">
|
||||
<p>I’ve been doing some reflecting this week on how I can work smarter (instead of harder), and one of the things I came up with was adding a few more tools to my Vim repertoire. I spend more than half of my engineering time in Vim (the other half usually being in a web browser), so I figured that a few minutes here and there would eventually add up in a big way.</p>
|
||||
<p>But like anything else with Vim, there are always multiple ways of accomplishing the very same thing, so I make no guarantees that there aren’t simpler ways of getting this done — but I can say that this way gets the job done, and is pretty easy to get working on your own system.</p>
|
||||
</div>
|
||||
|
||||
<%= player_data(@movie) %>
|
6
config.ru
Normal file
6
config.ru
Normal file
@ -0,0 +1,6 @@
|
||||
require "bundler/setup"
|
||||
Bundler.require
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), "app"))
|
||||
|
||||
run Sinatra::Application
|
3
config/init.rb
Normal file
3
config/init.rb
Normal file
@ -0,0 +1,3 @@
|
||||
Paperclip.configure do |config|
|
||||
config.use_dm_validations = true
|
||||
end
|
180
public/javascripts/ansi-interpreter.js
Normal file
180
public/javascripts/ansi-interpreter.js
Normal file
@ -0,0 +1,180 @@
|
||||
SP.AnsiInterpreter = function(terminal) {
|
||||
this.terminal = terminal;
|
||||
this.compilePatterns();
|
||||
}
|
||||
|
||||
SP.AnsiInterpreter.prototype = {
|
||||
PATTERNS: {
|
||||
"\x07": function(data) {
|
||||
console.log("bell!");
|
||||
},
|
||||
|
||||
"\x08": function(data) {
|
||||
// console.log("bs");
|
||||
this.terminal.bs();
|
||||
},
|
||||
|
||||
"\x0a": function(data) {
|
||||
this.terminal.cursorDown();
|
||||
},
|
||||
|
||||
"\x0d": function(data) {
|
||||
this.terminal.cr();
|
||||
},
|
||||
|
||||
"\x0e": function(data) {
|
||||
},
|
||||
|
||||
"\x0f": function(data) {
|
||||
},
|
||||
|
||||
"\x82": function(data) { // Reserved (?)
|
||||
},
|
||||
|
||||
"\x94": function(data) { // Cancel Character, ignore previous character
|
||||
},
|
||||
|
||||
// 20 - 7e
|
||||
"([\x20-\x7e]|\xe2..|[\xc5\xc4].)+": function(data, match) {
|
||||
this.terminal.print(match[0]);
|
||||
},
|
||||
|
||||
"\x1b\\(B": function(data) { // SCS (Set G0 Character SET)
|
||||
},
|
||||
|
||||
"\x1b\\[(?:[0-9]+)?(?:;[0-9]+)*([\x40-\x7e])": function(data, match) {
|
||||
this.params = [];
|
||||
var re = /(\d+)/g;
|
||||
var m;
|
||||
|
||||
while (m = re.exec(match[0])) {
|
||||
this.params.push(parseInt(m[1]));
|
||||
}
|
||||
|
||||
this.n = this.params[0];
|
||||
this.m = this.params[1];
|
||||
|
||||
this.handleCSI(match[1]);
|
||||
},
|
||||
|
||||
"\x1b\\[\\?([\x30-\x3f]+)([hlsr])": function(data, match) { // private standards
|
||||
// h = Sets DEC/xterm specific mode (http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html#decmode)
|
||||
// l = Resets mode (http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html#mode)
|
||||
// 1049 + h = Save cursor position, switch to alternate screen buffer, and clear screen.
|
||||
// 1049 + l = Clear screen, switch to normal screen buffer, and restore cursor position.
|
||||
// 1001 + s = ?
|
||||
// 1001 + r = ?
|
||||
|
||||
if (match[1] == '1049') {
|
||||
if (match[2] == 'h') {
|
||||
this.terminal.saveCursor();
|
||||
} else if (match[2] == 'l') {
|
||||
this.terminal.restoreCursor();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"\x1b\x3d": function(data) { // DECKPAM - Set keypad to applications mode (ESCape instead of digits)
|
||||
},
|
||||
|
||||
"\x1b\x3e": function(data) { // DECKPNM - Set keypad to numeric mode (digits intead of ESCape seq)
|
||||
},
|
||||
|
||||
"\x1b\\\x5d\x30\x3b(?:.)*?\x07": function(data, match) { // OSC - Operating System Command (terminal title)
|
||||
},
|
||||
|
||||
"\x1b\x37": function(data) { // save cursor pos and char attrs
|
||||
this.terminal.saveCursor();
|
||||
},
|
||||
|
||||
"\x1b\x38": function(data) { // restore cursor pos and char attrs
|
||||
this.terminal.restoreCursor();
|
||||
}
|
||||
},
|
||||
|
||||
handleCSI: function(term) {
|
||||
switch(term) {
|
||||
case "@":
|
||||
this.terminal.reserveCharacters(this.n);
|
||||
break;
|
||||
case "A":
|
||||
this.terminal.cursorUp(this.n || 1);
|
||||
break;
|
||||
case "B":
|
||||
this.terminal.cursorDown(this.n || 1);
|
||||
break;
|
||||
case "C":
|
||||
this.terminal.cursorForward(this.n || 1);
|
||||
break;
|
||||
case "D":
|
||||
this.terminal.cursorBack(this.n || 1);
|
||||
break;
|
||||
case "H":
|
||||
this.terminal.setCursorPos(this.n || 1, this.m || 1);
|
||||
break;
|
||||
case "J":
|
||||
this.terminal.eraseData(this.n || 0);
|
||||
break;
|
||||
case "K":
|
||||
this.terminal.eraseLine(this.n || 0);
|
||||
break;
|
||||
case "l": // l, Reset mode
|
||||
console.log("(TODO) reset: " + this.n);
|
||||
break;
|
||||
case "m":
|
||||
this.terminal.setSGR(this.params);
|
||||
break;
|
||||
case "r": // Set top and bottom margins (scroll region on VT100)
|
||||
break;
|
||||
default:
|
||||
console.log('no handler for CSI term: ' + term);
|
||||
}
|
||||
},
|
||||
|
||||
compilePatterns: function() {
|
||||
this.COMPILED_PATTERNS = [];
|
||||
var regexp;
|
||||
|
||||
for (re in this.PATTERNS) {
|
||||
regexp = new RegExp('^' + re);
|
||||
this.COMPILED_PATTERNS.push([regexp, this.PATTERNS[re]]);
|
||||
}
|
||||
},
|
||||
|
||||
feed: function(data) {
|
||||
if (data.length == 0) return;
|
||||
|
||||
// console.log(data);
|
||||
|
||||
var match;
|
||||
var handler;
|
||||
|
||||
for (var i=0; i<this.COMPILED_PATTERNS.length; i++) {
|
||||
var pattern = this.COMPILED_PATTERNS[i];
|
||||
match = pattern[0].exec(data);
|
||||
if (match) {
|
||||
handler = pattern[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
|
||||
handler.call(this, data, match);
|
||||
this.feed(data.slice(match[0].length));
|
||||
|
||||
} else {
|
||||
|
||||
var s = data.slice(0, 10);
|
||||
var hex = '';
|
||||
for (i=0; i<s.length; i++) {
|
||||
hex += '0x' + s[i].charCodeAt(0).toString(16) + ',';
|
||||
}
|
||||
console.log("failed matching: '" + s + "' (" + hex + ")");
|
||||
|
||||
throw 'bummer';
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
10
public/javascripts/misc.js
Normal file
10
public/javascripts/misc.js
Normal file
@ -0,0 +1,10 @@
|
||||
Function.prototype.bind = function(object) {
|
||||
var func = this;
|
||||
return function() {
|
||||
return func.apply(object, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
String.prototype.times = function(n) {
|
||||
return Array.prototype.join.call({length:n+1}, this);
|
||||
};
|
54
public/javascripts/player.js
Normal file
54
public/javascripts/player.js
Normal file
@ -0,0 +1,54 @@
|
||||
var SP = {};
|
||||
|
||||
var speed = 1.0;
|
||||
|
||||
SP.Player = function(cols, lines, data, time) {
|
||||
this.terminal = new SP.Terminal(cols, lines);
|
||||
this.interpreter = new SP.AnsiInterpreter(this.terminal);
|
||||
this.data = data;
|
||||
this.time = time;
|
||||
this.dataIndex = 0;
|
||||
this.frame = 0;
|
||||
this.currentData = "";
|
||||
console.log("started");
|
||||
this.nextFrame();
|
||||
};
|
||||
|
||||
SP.Player.prototype = {
|
||||
nextFrame: function() {
|
||||
var timing = this.time[this.frame];
|
||||
|
||||
if (!timing) {
|
||||
console.log("finished");
|
||||
return;
|
||||
}
|
||||
|
||||
this.terminal.restartCursorBlink();
|
||||
|
||||
// setTimeout(function() {
|
||||
// console.log(this.dataIndex);
|
||||
// console.log(this.currentData);
|
||||
this.interpreter.feed(this.currentData);
|
||||
this.terminal.updateDirtyLines();
|
||||
var n = timing[1];
|
||||
console.log(timing[0]);
|
||||
console.log(n);
|
||||
this.currentData = this.data.slice(this.dataIndex, this.dataIndex + n);
|
||||
this.dataIndex += n;
|
||||
this.frame += 1;
|
||||
if (!window.stopped) {
|
||||
this.nextFrame();
|
||||
}
|
||||
// }.bind(this), timing[0] * 1000 * (1.0 / speed));
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$(window).bind('keyup', function(event) {
|
||||
if (event.keyCode == 27) {
|
||||
window.stopped = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(function() { new SP.Player(cols, lines, data, time) });
|
429
public/javascripts/terminal.js
Normal file
429
public/javascripts/terminal.js
Normal file
@ -0,0 +1,429 @@
|
||||
/* var CP437_DICT = {
|
||||
'\x01' : ["☺", "WHITE SMILING FACE"],
|
||||
'\x02' : ["☻", "BLACK SMILING FACE"],
|
||||
'\x03' : ["♥", "BLACK HEART SUIT"],
|
||||
'\x04' : ["♦", "BLACK DIAMOND SUIT"],
|
||||
'\x05' : ["♣", "BLACK CLUB SUIT"],
|
||||
'\x06' : ["♠", "BLACK SPADE SUIT"],
|
||||
'\x07' : ["•", "BULLET"],
|
||||
'\x08' : ["◘", "INVERSE BULLET"],
|
||||
'\x09' : ["○", "WHITE CIRCLE"],
|
||||
'\x0a' : ["◙", "INVERSE WHITE CIRCLE"],
|
||||
'\x0b' : ["♂", "MALE SIGN"],
|
||||
'\x0c' : ["♀", "FEMALE SIGN"],
|
||||
'\x0d' : ["♪", "EIGHTH NOTE"],
|
||||
'\x0e' : ["♫", "BEAMED EIGHTH NOTES"],
|
||||
'\x0f' : ["☼", "WHITE SUN WITH RAYS"],
|
||||
'\x10' : ["▸", "BLACK RIGHT-POINTING SMALL TRIANGLE"],
|
||||
'\x11' : ["◂", "BLACK LEFT-POINTING SMALL TRIANGLE"],
|
||||
'\x12' : ["↕", "UP DOWN ARROW"],
|
||||
'\x13' : ["‼", "DOUBLE EXCLAMATION MARK"],
|
||||
'\x14' : ["¶", "PILCROW SIGN"],
|
||||
'\x15' : ["§", "SECTION SIGN"],
|
||||
'\x16' : ["▬", "BLACK RECTANGLE"],
|
||||
'\x17' : ["↨", "UP DOWN ARROW WITH BASE"],
|
||||
'\x18' : ["↑", "UPWARDS ARROW"],
|
||||
'\x19' : ["↓", "DOWNWARDS ARROW"],
|
||||
'\x1a' : ["→", "RIGHTWARDS ARROW"],
|
||||
'\x1b' : ["←", "LEFTWARDS ARROW"],
|
||||
'\x1c' : ["∟", "RIGHT ANGLE"],
|
||||
'\x1d' : ["↔", "LEFT RIGHT ARROW"],
|
||||
'\x1e' : ["▴", "BLACK UP-POINTING SMALL TRIANGLE"],
|
||||
'\x1f' : ["▾", "BLACK DOWN-POINTING SMALL TRIANGLE"],
|
||||
'\x21' : ["!", "EXCLAMATION MARK"],
|
||||
'\x22' : [""", "QUOTATION MARK"],
|
||||
'\x23' : ["#", "NUMBER SIGN"],
|
||||
'\x24' : ["$", "DOLLAR SIGN"],
|
||||
'\x25' : ["%", "PERCENT SIGN"],
|
||||
'\x26' : ["&", "AMPERSAND"],
|
||||
'\x27' : ["'", "APOSTROPHE"],
|
||||
'\x28' : ["(", "LEFT PARENTHESIS"],
|
||||
'\x29' : [")", "RIGHT PARENTHESIS"],
|
||||
'\x2a' : ["*", "ASTERISK"],
|
||||
'\x2b' : ["+", "PLUS SIGN"],
|
||||
'\x2c' : [",", "COMMA"],
|
||||
'\x2d' : ["-", "HYPHEN-MINUS"],
|
||||
'\x2e' : [".", "FULL STOP"],
|
||||
'\x2f' : ["/", "SOLIDUS"],
|
||||
'\x7f' : ["⌂", "HOUSE"],
|
||||
'\x80' : ["Ç", "LATIN CAPITAL LETTER C WITH CEDILLA"],
|
||||
'\x81' : ["ü", "LATIN SMALL LETTER U WITH DIAERESIS"],
|
||||
'\x82' : ["é", "LATIN SMALL LETTER E WITH ACUTE"],
|
||||
'\x83' : ["â", "LATIN SMALL LETTER A WITH CIRCUMFLEX"],
|
||||
'\x84' : ["ä", "LATIN SMALL LETTER A WITH DIAERESIS"],
|
||||
'\x85' : ["à", "LATIN SMALL LETTER A WITH GRAVE"],
|
||||
'\x86' : ["å", "LATIN SMALL LETTER A WITH RING ABOVE"],
|
||||
'\x87' : ["ç", "LATIN SMALL LETTER C WITH CEDILLA"],
|
||||
'\x88' : ["ê", "LATIN SMALL LETTER E WITH CIRCUMFLEX"],
|
||||
'\x89' : ["ë", "LATIN SMALL LETTER E WITH DIAERESIS"],
|
||||
'\x8a' : ["è", "LATIN SMALL LETTER E WITH GRAVE"],
|
||||
'\x8b' : ["ï", "LATIN SMALL LETTER I WITH DIAERESIS"],
|
||||
'\x8c' : ["î", "LATIN SMALL LETTER I WITH CIRCUMFLEX"],
|
||||
'\x8d' : ["ì", "LATIN SMALL LETTER I WITH GRAVE"],
|
||||
'\x8e' : ["Ä", "LATIN CAPITAL LETTER A WITH DIAERESIS"],
|
||||
'\x8f' : ["Å", "LATIN CAPITAL LETTER A WITH RING ABOVE"],
|
||||
'\x90' : ["É", "LATIN CAPITAL LETTER E WITH ACUTE"],
|
||||
'\x91' : ["æ", "LATIN SMALL LETTER AE"],
|
||||
'\x92' : ["Æ", "LATIN CAPITAL LETTER AE"],
|
||||
'\x93' : ["ô", "LATIN SMALL LETTER O WITH CIRCUMFLEX"],
|
||||
'\x94' : ["ö", "LATIN SMALL LETTER O WITH DIAERESIS"],
|
||||
'\x95' : ["ò", "LATIN SMALL LETTER O WITH GRAVE"],
|
||||
'\x96' : ["û", "LATIN SMALL LETTER U WITH CIRCUMFLEX"],
|
||||
'\x97' : ["ù", "LATIN SMALL LETTER U WITH GRAVE"],
|
||||
'\x98' : ["ÿ", "LATIN SMALL LETTER Y WITH DIAERESIS"],
|
||||
'\x99' : ["Ö", "LATIN CAPITAL LETTER O WITH DIAERESIS"],
|
||||
'\x9a' : ["Ü", "LATIN CAPITAL LETTER U WITH DIAERESIS"],
|
||||
'\x9b' : ["¢", "CENT SIGN"],
|
||||
'\x9c' : ["£", "POUND SIGN"],
|
||||
'\x9d' : ["¥", "YEN SIGN"],
|
||||
'\x9e' : ["₧", "PESETA SIGN"],
|
||||
'\x9f' : ["ƒ", "LATIN SMALL LETTER F WITH HOOK"],
|
||||
'\xa0' : ["á", "LATIN SMALL LETTER A WITH ACUTE"],
|
||||
'\xa1' : ["í", "LATIN SMALL LETTER I WITH ACUTE"],
|
||||
'\xa2' : ["ó", "LATIN SMALL LETTER O WITH ACUTE"],
|
||||
'\xa3' : ["ú", "LATIN SMALL LETTER U WITH ACUTE"],
|
||||
'\xa4' : ["ñ", "LATIN SMALL LETTER N WITH TILDE"],
|
||||
'\xa5' : ["Ñ", "LATIN CAPITAL LETTER N WITH TILDE"],
|
||||
'\xa6' : ["ª", "FEMININE ORDINAL INDICATOR"],
|
||||
'\xa7' : ["º", "MASCULINE ORDINAL INDICATOR"],
|
||||
'\xa8' : ["¿", "INVERTED QUESTION MARK"],
|
||||
'\xa9' : ["⌐", "REVERSED NOT SIGN"],
|
||||
'\xaa' : ["¬", "NOT SIGN"],
|
||||
'\xab' : ["½", "VULGAR FRACTION ONE HALF"],
|
||||
'\xac' : ["¼", "VULGAR FRACTION ONE QUARTER"],
|
||||
'\xad' : ["¡", "INVERTED EXCLAMATION MARK"],
|
||||
'\xae' : ["«", "LEFT-POINTING DOUBLE ANGLE QUOTATION MARK"],
|
||||
'\xaf' : ["»", "RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK"],
|
||||
'\xb0' : ["░", "LIGHT SHADE"],
|
||||
'\xb1' : ["▒", "MEDIUM SHADE"],
|
||||
'\xb2' : ["▓", "DARK SHADE"],
|
||||
'\xb3' : ["│", "BOX DRAWINGS LIGHT VERTICAL"],
|
||||
'\xb4' : ["┤", "BOX DRAWINGS LIGHT VERTICAL AND LEFT"],
|
||||
'\xb5' : ["╡", "BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE"],
|
||||
'\xb6' : ["╢", "BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE"],
|
||||
'\xb7' : ["╖", "BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE"],
|
||||
'\xb8' : ["╕", "BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE"],
|
||||
'\xb9' : ["╣", "BOX DRAWINGS DOUBLE VERTICAL AND LEFT"],
|
||||
'\xba' : ["║", "BOX DRAWINGS DOUBLE VERTICAL"],
|
||||
'\xbb' : ["╗", "BOX DRAWINGS DOUBLE DOWN AND LEFT"],
|
||||
'\xbc' : ["╝", "BOX DRAWINGS DOUBLE UP AND LEFT"],
|
||||
'\xbd' : ["╜", "BOX DRAWINGS UP DOUBLE AND LEFT SINGLE"],
|
||||
'\xbe' : ["╛", "BOX DRAWINGS UP SINGLE AND LEFT DOUBLE"],
|
||||
'\xbf' : ["┐", "BOX DRAWINGS LIGHT DOWN AND LEFT"],
|
||||
'\xc0' : ["└", "BOX DRAWINGS LIGHT UP AND RIGHT"],
|
||||
'\xc1' : ["┴", "BOX DRAWINGS LIGHT UP AND HORIZONTAL"],
|
||||
'\xc2' : ["┬", "BOX DRAWINGS LIGHT DOWN AND HORIZONTAL"],
|
||||
'\xc3' : ["├", "BOX DRAWINGS LIGHT VERTICAL AND RIGHT"],
|
||||
'\xc4' : ["─", "BOX DRAWINGS LIGHT HORIZONTAL"],
|
||||
'\xc5' : ["┼", "BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL"],
|
||||
'\xc6' : ["╞", "BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE"],
|
||||
'\xc7' : ["╟", "BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE"],
|
||||
'\xc8' : ["╚", "BOX DRAWINGS DOUBLE UP AND RIGHT"],
|
||||
'\xc9' : ["╔", "BOX DRAWINGS DOUBLE DOWN AND RIGHT"],
|
||||
'\xca' : ["╩", "BOX DRAWINGS DOUBLE UP AND HORIZONTAL"],
|
||||
'\xcb' : ["╦", "BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL"],
|
||||
'\xcc' : ["╠", "BOX DRAWINGS DOUBLE VERTICAL AND RIGHT"],
|
||||
'\xcd' : ["═", "BOX DRAWINGS DOUBLE HORIZONTAL"],
|
||||
'\xce' : ["╬", "BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL"],
|
||||
'\xcf' : ["╧", "BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE"],
|
||||
'\xd0' : ["╨", "BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE"],
|
||||
'\xd1' : ["╤", "BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE"],
|
||||
'\xd2' : ["╥", "BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE"],
|
||||
'\xd3' : ["╙", "BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE"],
|
||||
'\xd4' : ["╘", "BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE"],
|
||||
'\xd5' : ["╒", "BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE"],
|
||||
'\xd6' : ["╓", "BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE"],
|
||||
'\xd7' : ["╫", "BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE"],
|
||||
'\xd8' : ["╪", "BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE"],
|
||||
'\xd9' : ["┘", "BOX DRAWINGS LIGHT UP AND LEFT"],
|
||||
'\xda' : ["┌", "BOX DRAWINGS LIGHT DOWN AND RIGHT"],
|
||||
'\xdb' : ["█", "FULL BLOCK"],
|
||||
'\xdc' : ["▄", "LOWER HALF BLOCK"],
|
||||
'\xdd' : ["▌", "LEFT HALF BLOCK"],
|
||||
'\xde' : ["▐", "RIGHT HALF BLOCK"],
|
||||
'\xdf' : ["▀", "UPPER HALF BLOCK"],
|
||||
'\xe0' : ["α", "GREEK SMALL LETTER ALPHA"],
|
||||
'\xe1' : ["β", "GREEK SMALL LETTER BETA"],
|
||||
'\xe2' : ["Γ", "GREEK CAPITAL LETTER GAMMA"],
|
||||
'\xe3' : ["π", "GREEK SMALL LETTER PI"],
|
||||
'\xe4' : ["Σ", "GREEK CAPITAL LETTER SIGMA"],
|
||||
'\xe5' : ["σ", "GREEK SMALL LETTER SIGMA"],
|
||||
'\xe6' : ["µ", "MICRO SIGN"],
|
||||
'\xe7' : ["τ", "GREEK SMALL LETTER TAU"],
|
||||
'\xe8' : ["Φ", "GREEK CAPITAL LETTER PHI"],
|
||||
'\xe9' : ["Θ", "GREEK CAPITAL LETTER THETA"],
|
||||
'\xea' : ["Ω", "GREEK CAPITAL LETTER OMEGA"],
|
||||
'\xeb' : ["δ", "GREEK SMALL LETTER DELTA"],
|
||||
'\xec' : ["∞", "INFINITY"],
|
||||
'\xed' : ["∅", "EMPTY SET"],
|
||||
'\xee' : ["∈", "ELEMENT OF"],
|
||||
'\xef' : ["∩", "INTERSECTION"],
|
||||
'\xf0' : ["≡", "IDENTICAL TO"],
|
||||
'\xf1' : ["±", "PLUS-MINUS SIGN"],
|
||||
'\xf2' : ["≥", "GREATER-THAN OR EQUAL TO"],
|
||||
'\xf3' : ["≤", "LESS-THAN OR EQUAL TO"],
|
||||
'\xf4' : ["⌠", "TOP HALF INTEGRAL"],
|
||||
'\xf5' : ["⌡", "BOTTOM HALF INTEGRAL"],
|
||||
'\xf6' : ["÷", "DIVISION SIGN"],
|
||||
'\xf7' : ["≈", "ALMOST EQUAL TO"],
|
||||
'\xf8' : ["°", "DEGREE SIGN"],
|
||||
'\xf9' : ["∙", "BULLET OPERATOR"],
|
||||
'\xfa' : ["·", "MIDDLE DOT"],
|
||||
'\xfb' : ["√", "SQUARE ROOT"],
|
||||
'\xfc' : ["ⁿ", "SUPERSCRIPT LATIN SMALL LETTER N"],
|
||||
'\xfd' : ["²", "SUPERSCRIPT TWO"],
|
||||
'\xfe' : ["▪", "SMALL BLACK SQUARE"]
|
||||
}
|
||||
*/
|
||||
|
||||
SP.Terminal = function(cols, lines) {
|
||||
this.cols = cols;
|
||||
this.lines = lines;
|
||||
this.cursorLine = 0;
|
||||
this.cursorCol = 0;
|
||||
this.lineData = [];
|
||||
this.fg = this.bg = undefined;
|
||||
this.dirtyLines = [];
|
||||
this.initialize();
|
||||
};
|
||||
|
||||
SP.Terminal.prototype = {
|
||||
initialize: function() {
|
||||
var container = $(".player .term");
|
||||
this.element = container;
|
||||
for (l = 0; l < this.lines; l++) {
|
||||
var row = $("<span class='line'>");
|
||||
container.append(row);
|
||||
container.append("\n");
|
||||
this.lineData[l] = [];
|
||||
this.updateLine(l);
|
||||
}
|
||||
},
|
||||
|
||||
setSGR: function(codes) {
|
||||
if (codes.length == 0) {
|
||||
codes = [0];
|
||||
}
|
||||
|
||||
for (var i=0; i<codes.length; i++) {
|
||||
var n = codes[i];
|
||||
|
||||
if (n === 0) {
|
||||
this.fg = this.bg = undefined;
|
||||
this.bright = false;
|
||||
} else if (n == 1) {
|
||||
this.bright = true;
|
||||
} else if (n >= 30 && n <= 37) {
|
||||
this.fg = n - 30;
|
||||
} else if (n >= 40 && n <= 47) {
|
||||
this.bg = n - 40;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateLine: function(n) {
|
||||
n = (typeof n != "undefined" ? n : this.cursorLine);
|
||||
this.dirtyLines.push(n);
|
||||
},
|
||||
|
||||
updateDirtyLines: function() {
|
||||
var updated = [];
|
||||
|
||||
for (var i=0; i<this.dirtyLines.length; i++) {
|
||||
var n = this.dirtyLines[i];
|
||||
if (updated.indexOf(n) == -1) {
|
||||
this._updateLine(n);
|
||||
updated.push(n);
|
||||
}
|
||||
}
|
||||
|
||||
this.dirtyLines = [];
|
||||
},
|
||||
|
||||
_updateLine: function(n) {
|
||||
var html;
|
||||
|
||||
if (n == this.cursorLine) {
|
||||
var text = this.lineData[n];
|
||||
html = text.slice(0, this.cursorCol).concat(['<span class="cursor">' + (text[this.cursorCol] || '') + "</span>"], text.slice(this.cursorCol + 1) || []);
|
||||
} else {
|
||||
html = this.lineData[n];
|
||||
}
|
||||
|
||||
this.element.find(".line:eq(" + n + ")").html(html.join(''));
|
||||
},
|
||||
|
||||
setCursorPos: function(line, col) {
|
||||
line -= 1;
|
||||
col -= 1;
|
||||
var oldLine = this.cursorLine;
|
||||
this.cursorLine = line;
|
||||
this.cursorCol = col;
|
||||
this.updateLine(oldLine);
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
saveCursor: function() {
|
||||
this.savedCol = this.cursorCol;
|
||||
this.savedLine = this.cursorLine;
|
||||
},
|
||||
|
||||
restoreCursor: function() {
|
||||
var oldLine = this.cursorLine;
|
||||
|
||||
this.cursorLine = this.savedLine;
|
||||
this.cursorCol = this.savedCol;
|
||||
|
||||
this.updateLine(oldLine);
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
cursorLeft: function() {
|
||||
if (this.cursorCol > 0)
|
||||
this.cursorCol = this.cursorCol - 1;
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
cursorRight: function() {
|
||||
if (this.cursorCol < this.cols)
|
||||
this.cursorCol = this.cursorCol + 1;
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
cursorUp: function() {
|
||||
if (this.cursorLine > 0)
|
||||
this.cursorLine = this.cursorLine - 1;
|
||||
this.updateLine(this.cursorLine);
|
||||
this.updateLine(this.cursorLine+1);
|
||||
},
|
||||
|
||||
cursorDown: function() {
|
||||
if (this.cursorLine < this.lines)
|
||||
this.cursorLine = this.cursorLine + 1;
|
||||
this.updateLine(this.cursorLine);
|
||||
this.updateLine(this.cursorLine-1);
|
||||
},
|
||||
|
||||
cursorForward: function(n) {
|
||||
for (var i=0; i<n; i++) this.cursorRight();
|
||||
},
|
||||
|
||||
cursorBack: function(n) {
|
||||
for (var i=0; i<n; i++) this.cursorLeft();
|
||||
},
|
||||
|
||||
cr: function() {
|
||||
this.cursorCol = 0;
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
bs: function() {
|
||||
if (this.cursorCol > 0) {
|
||||
this.lineData[this.cursorLine][this.cursorCol - 1] = ' ';
|
||||
this.cursorCol = this.cursorCol - 1;
|
||||
this.updateLine();
|
||||
}
|
||||
},
|
||||
|
||||
print: function(text) {
|
||||
text = Utf8.decode(text);
|
||||
|
||||
for (var i=0; i<text.length; i++) {
|
||||
this.fill(this.cursorLine, this.cursorCol, 1, text[i]);
|
||||
this.cursorCol = this.cursorCol + 1;
|
||||
}
|
||||
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
eraseData: function(n) {
|
||||
if (n == 0) {
|
||||
this.eraseLine(n);
|
||||
for (var l=this.cursorLine+1; l<this.lines; l++) {
|
||||
this.lineData[l] = [];
|
||||
this.updateLine(l);
|
||||
}
|
||||
} else if (n == 1) {
|
||||
for (var l=0; l<this.cursorLine; l++) {
|
||||
this.lineData[l] = [];
|
||||
this.updateLine(l);
|
||||
}
|
||||
this.eraseLine(n);
|
||||
} else if (n == 2) {
|
||||
for (var l=0; l<this.lines; l++) {
|
||||
this.lineData[l] = [];
|
||||
this.updateLine(l);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
eraseLine: function(n) {
|
||||
if (n == 0) {
|
||||
this.fill(this.cursorLine, this.cursorCol, this.cols - this.cursorCol, ' ');
|
||||
// this.lineData[this.cursorLine] = this.lineData[this.cursorLine].slice(0, this.cursorCol);
|
||||
// this.lineData[this.cursorLine] = this.lineData[this.cursorLine].slice(0, this.cursorCol) + " ".times(this.cols - this.cursorCol);
|
||||
this.updateLine(this.cursorLine);
|
||||
} else if (n == 1) {
|
||||
this.fill(this.cursorLine, 0, this.cursorCol, ' ');
|
||||
// this.lineData[this.cursorLine] = " ".times(this.cursorCol).split('').concat(this.lineData[this.cursorLine].slice(this.cursorCol));
|
||||
// this.lineData[this.cursorLine] = " ".times(this.cursorCol) + this.lineData[this.cursorLine].slice(this.cursorCol);
|
||||
this.updateLine(this.cursorLine);
|
||||
} else if (n == 2) {
|
||||
this.fill(this.cursorLine, 0, this.cols, ' ');
|
||||
// this.lineData[this.cursorLine] = [] // " ".times(this.cols);
|
||||
this.updateLine(this.cursorLine);
|
||||
}
|
||||
},
|
||||
|
||||
reserveCharacters: function(n) {
|
||||
var line = this.lineData[this.cursorLine];
|
||||
this.lineData[this.cursorLine] = line.slice(0, this.cursorCol).concat(" ".times(n).split(''), line.slice(this.cursorCol, this.cols - n));
|
||||
this.updateLine();
|
||||
},
|
||||
|
||||
fill: function(line, col, n, char) {
|
||||
var prefix = '', postfix = '';
|
||||
|
||||
if (this.fg !== undefined || this.bg !== undefined || this.bright) {
|
||||
prefix = '<span class="';
|
||||
var brightOffset = this.bright ? 8 : 0;
|
||||
|
||||
if (this.fg !== undefined) {
|
||||
prefix += ' fg' + (this.fg + brightOffset);
|
||||
} else if (this.bright) {
|
||||
prefix += ' bright';
|
||||
}
|
||||
|
||||
if (this.bg !== undefined) {
|
||||
prefix += ' bg' + this.bg;
|
||||
}
|
||||
|
||||
prefix += '">';
|
||||
postfix = '</span>';
|
||||
}
|
||||
|
||||
var char = prefix + char + postfix;
|
||||
|
||||
for (var i=0; i<n; i++) {
|
||||
this.lineData[line][col+i] = char;
|
||||
}
|
||||
// this.lineData[line] = this.lineData[line].slice(0, col).concat(char, this.lineData[line].slice(col + 1));
|
||||
},
|
||||
|
||||
blinkCursor: function() {
|
||||
var cursor = this.element.find(".cursor");
|
||||
if (cursor.hasClass("inverted")) {
|
||||
cursor.removeClass("inverted");
|
||||
} else {
|
||||
cursor.addClass("inverted");
|
||||
}
|
||||
},
|
||||
|
||||
restartCursorBlink: function() {
|
||||
if (this.cursorTimerId) {
|
||||
clearInterval(this.cursorTimerId);
|
||||
this.cursorTimerId = null;
|
||||
}
|
||||
this.cursorTimerId = setInterval(this.blinkCursor.bind(this), 500);
|
||||
}
|
||||
};
|
68
public/javascripts/utf8.js
Normal file
68
public/javascripts/utf8.js
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
*
|
||||
* UTF-8 data encode / decode
|
||||
* http://www.webtoolkit.info/
|
||||
*
|
||||
**/
|
||||
|
||||
var Utf8 = {
|
||||
|
||||
// public method for url encoding
|
||||
encode : function (string) {
|
||||
string = string.replace(/\r\n/g,"\n");
|
||||
var utftext = "";
|
||||
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
|
||||
var c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return utftext;
|
||||
},
|
||||
|
||||
// public method for url decoding
|
||||
decode : function (utftext) {
|
||||
var string = "";
|
||||
var i = 0;
|
||||
var c = c1 = c2 = 0;
|
||||
|
||||
while ( i < utftext.length ) {
|
||||
|
||||
c = utftext.charCodeAt(i);
|
||||
|
||||
if (c < 128) {
|
||||
string += String.fromCharCode(c);
|
||||
i++;
|
||||
}
|
||||
else if((c > 191) && (c < 224)) {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
c3 = utftext.charCodeAt(i+2);
|
||||
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
183
public/stylesheets/main.css
Normal file
183
public/stylesheets/main.css
Normal file
@ -0,0 +1,183 @@
|
||||
.clear {
|
||||
clear: both;
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #E7E7DE;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body, div, p {
|
||||
font-family: arial, helvetica;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 325A66 */
|
||||
/* DEA140 */
|
||||
/* A32B26 */
|
||||
/* 590D0B */
|
||||
|
||||
h1 {
|
||||
color: #3e3e3e;
|
||||
font-family: 'Trebuchet MS';
|
||||
font-size: 42px;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #3e3e3e;
|
||||
font-family: 'Trebuchet MS';
|
||||
font-size: 26px;
|
||||
padding: 15px 15px 40px 15px;
|
||||
}
|
||||
|
||||
#top {
|
||||
position: relative;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
width: 300px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#menu {
|
||||
display: block;
|
||||
width: 300px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
font-size: 11px;
|
||||
font-family: Verdana;
|
||||
}
|
||||
|
||||
#menu .links {
|
||||
background-color: #172322;
|
||||
list-style: none;
|
||||
padding: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
|
||||
#menu .links li {
|
||||
color: #eee;
|
||||
display: inline-block;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#all {
|
||||
margin: 0 auto;
|
||||
width: 980px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#main {
|
||||
background-color: white;
|
||||
width: 980px;
|
||||
font-size: 11px;
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.player {
|
||||
/* border: 1px solid #777;*/
|
||||
/* background-color: #333;*/
|
||||
float: left;
|
||||
display: block;
|
||||
padding: 0px;
|
||||
margin: 0px 0px 30px 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.term {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
display: block;
|
||||
font-family: 'Droid Sans Mono', Monospace;
|
||||
white-space: pre;
|
||||
background-color: black;
|
||||
line-height: 1.2em;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.term .line {
|
||||
font-size: 12px;
|
||||
/* background-color: black;*/
|
||||
/* padding: 0;*/
|
||||
/* margin: 0;*/
|
||||
}
|
||||
|
||||
.line .cursor {
|
||||
background-color: #D3D7CF;
|
||||
}
|
||||
|
||||
.line span.cursor.inverted {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.hud {
|
||||
background-color: #333;
|
||||
opacity: 0.85;
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
bottom: 10px;
|
||||
display: none;
|
||||
height: 30px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.player:hover .hud {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.fg0 { color: #000000 }
|
||||
.fg1 { color: #CC0000 }
|
||||
.fg2 { color: #4E9A06 }
|
||||
.fg3 { color: #C4A000 }
|
||||
.fg4 { color: #3465A4 }
|
||||
.fg5 { color: #75507B }
|
||||
.fg6 { color: #06989A }
|
||||
.fg7 { color: #D3D7CF }
|
||||
.fg8 { color: #555753; font-weight: bold }
|
||||
.fg9 { color: #EF2929; font-weight: bold }
|
||||
.fg10 { color: #8AE234; font-weight: bold }
|
||||
.fg11 { color: #FCE94F; font-weight: bold }
|
||||
.fg12 { color: #729FCF; font-weight: bold }
|
||||
.fg13 { color: #AD7FA8; font-weight: bold }
|
||||
.fg14 { color: #34E2E2; font-weight: bold }
|
||||
.fg15 { color: #EEEEEC; font-weight: bold }
|
||||
|
||||
.bright { font-weight: bold }
|
||||
|
||||
.bg0 { background-color: #000000 }
|
||||
.bg1 { background-color: #CC0000 }
|
||||
.bg2 { background-color: #4E9A06 }
|
||||
.bg3 { background-color: #C4A000 }
|
||||
.bg4 { background-color: #3465A4 }
|
||||
.bg5 { background-color: #75507B }
|
||||
.bg6 { background-color: #06989A }
|
||||
.bg7 { background-color: #D3D7CF }
|
||||
.bg8 { background-color: #555753 }
|
||||
.bg9 { background-color: #EF2929 }
|
||||
.bg10 { background-color: #8AE234 }
|
||||
.bg11 { background-color: #FCE94F }
|
||||
.bg12 { background-color: #729FCF }
|
||||
.bg13 { background-color: #AD7FA8 }
|
||||
.bg14 { background-color: #34E2E2 }
|
||||
.bg15 { background-color: #EEEEEC }
|
||||
|
||||
.description {
|
||||
color: #666;
|
||||
font-family: arial, helvetica;
|
||||
font-size: 16px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.description p {
|
||||
margin-bottom: 20px;
|
||||
}
|
88
public/stylesheets/reset.css
Normal file
88
public/stylesheets/reset.css
Normal file
@ -0,0 +1,88 @@
|
||||
/* html5doctor.com Reset Stylesheet v1.6.1
|
||||
Last Updated: 2010-09-17
|
||||
Author: Richard Clark - http://richclarkdesign.com
|
||||
*/
|
||||
html, body, div, span, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
abbr, address, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, samp,
|
||||
small, strong, sub, sup, var,
|
||||
b, i,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin:0;
|
||||
padding:0;
|
||||
border:0;
|
||||
outline:0;
|
||||
font-size:100%;
|
||||
vertical-align:baseline;
|
||||
background:transparent;
|
||||
}
|
||||
body {
|
||||
line-height:1;
|
||||
}
|
||||
article,aside,details,figcaption,figure,
|
||||
footer,header,hgroup,menu,nav,section {
|
||||
display:block;
|
||||
}
|
||||
nav ul {
|
||||
list-style:none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes:none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content:'';
|
||||
content:none;
|
||||
}
|
||||
a {
|
||||
margin:0;
|
||||
padding:0;
|
||||
font-size:100%;
|
||||
vertical-align:baseline;
|
||||
background:transparent;
|
||||
}
|
||||
/* change colours to suit your needs */
|
||||
ins {
|
||||
background-color:#ff9;
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
}
|
||||
/* change colours to suit your needs */
|
||||
mark {
|
||||
background-color:#ff9;
|
||||
color:#000;
|
||||
font-style:italic;
|
||||
font-weight:bold;
|
||||
}
|
||||
del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
abbr[title], dfn[title] {
|
||||
border-bottom:1px dotted;
|
||||
cursor:help;
|
||||
}
|
||||
table {
|
||||
border-collapse:collapse;
|
||||
border-spacing:0;
|
||||
}
|
||||
/* change border colour to suit your needs */
|
||||
hr {
|
||||
display:block;
|
||||
height:1px;
|
||||
border:0;
|
||||
border-top:1px solid #cccccc;
|
||||
margin:1em 0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
input, select {
|
||||
vertical-align:middle;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user