-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
0 parents
commit 6f1d8ee
Showing
20 changed files
with
10,143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.DS_Store | ||
Gemfile.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
source 'https://rubygems.org' | ||
|
||
gem 'opal', :github => 'opal/opal' | ||
gem 'opal-jquery', :github => 'opal/opal-jquery' | ||
|
||
gem "middleman" | ||
gem "middleman-sprockets" | ||
gem "middleman-gh-pages" | ||
|
||
gem 'haml' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Opal Playground | ||
|
||
**Very alpha - only just works** | ||
|
||
Install dependencies: | ||
|
||
``` | ||
bundle install | ||
``` | ||
|
||
Run middleman server: | ||
|
||
``` | ||
bundle exec middleman server | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
require 'bundler' | ||
Bundler.require | ||
|
||
require 'middleman-gh-pages' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
require 'bundler' | ||
Bundler.require | ||
|
||
activate :sprockets | ||
|
||
activate :directory_indexes | ||
|
||
set :css_dir, 'stylesheets' | ||
|
||
set :js_dir, 'javascripts' | ||
|
||
set :images_dir, 'images' | ||
|
||
after_configuration do | ||
Opal.paths.each do |p| | ||
sprockets.append_path p | ||
end | ||
end | ||
|
||
configure :build do | ||
activate :minify_css | ||
activate :minify_javascript | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
require 'bundler' | ||
Bundler.require | ||
|
||
require 'middleman/rack' | ||
|
||
run Middleman.server |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
!!! | ||
%html | ||
%head | ||
= stylesheet_link_tag 'application' | ||
= javascript_include_tag 'application' | ||
|
||
%body | ||
%nav.navbar.navbar-default | ||
.navbar-header | ||
%a.navbar-brand Opal Playground | ||
.container | ||
.collapse.navbar-collapse | ||
%ul.nav.navbar-nav | ||
%li | ||
%button.btn.btn-primary#run-code | ||
Run Code (Cmd+Enter) | ||
|
||
.row | ||
.col-md-6 | ||
.top-pane#html_pane | ||
.bottom-pane#ruby_pane | ||
|
||
.col-md-6 | ||
.top-pane#css_pane | ||
.bottom-pane#result_pane | ||
%iframe#result-frame(frameborder="0") |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,338 @@ | ||
CodeMirror.defineMode("xml", function(config, parserConfig) { | ||
var indentUnit = config.indentUnit; | ||
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1; | ||
var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag || true; | ||
|
||
var Kludges = parserConfig.htmlMode ? { | ||
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, | ||
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, | ||
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, | ||
'track': true, 'wbr': true}, | ||
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, | ||
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, | ||
'th': true, 'tr': true}, | ||
contextGrabbers: { | ||
'dd': {'dd': true, 'dt': true}, | ||
'dt': {'dd': true, 'dt': true}, | ||
'li': {'li': true}, | ||
'option': {'option': true, 'optgroup': true}, | ||
'optgroup': {'optgroup': true}, | ||
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, | ||
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, | ||
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, | ||
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, | ||
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, | ||
'rp': {'rp': true, 'rt': true}, | ||
'rt': {'rp': true, 'rt': true}, | ||
'tbody': {'tbody': true, 'tfoot': true}, | ||
'td': {'td': true, 'th': true}, | ||
'tfoot': {'tbody': true}, | ||
'th': {'td': true, 'th': true}, | ||
'thead': {'tbody': true, 'tfoot': true}, | ||
'tr': {'tr': true} | ||
}, | ||
doNotIndent: {"pre": true}, | ||
allowUnquoted: true, | ||
allowMissing: true | ||
} : { | ||
autoSelfClosers: {}, | ||
implicitlyClosed: {}, | ||
contextGrabbers: {}, | ||
doNotIndent: {}, | ||
allowUnquoted: false, | ||
allowMissing: false | ||
}; | ||
var alignCDATA = parserConfig.alignCDATA; | ||
|
||
// Return variables for tokenizers | ||
var tagName, type, setStyle; | ||
|
||
function inText(stream, state) { | ||
function chain(parser) { | ||
state.tokenize = parser; | ||
return parser(stream, state); | ||
} | ||
|
||
var ch = stream.next(); | ||
if (ch == "<") { | ||
if (stream.eat("!")) { | ||
if (stream.eat("[")) { | ||
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); | ||
else return null; | ||
} else if (stream.match("--")) { | ||
return chain(inBlock("comment", "-->")); | ||
} else if (stream.match("DOCTYPE", true, true)) { | ||
stream.eatWhile(/[\w\._\-]/); | ||
return chain(doctype(1)); | ||
} else { | ||
return null; | ||
} | ||
} else if (stream.eat("?")) { | ||
stream.eatWhile(/[\w\._\-]/); | ||
state.tokenize = inBlock("meta", "?>"); | ||
return "meta"; | ||
} else { | ||
var isClose = stream.eat("/"); | ||
tagName = ""; | ||
var c; | ||
while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; | ||
if (!tagName) return "tag error"; | ||
type = isClose ? "closeTag" : "openTag"; | ||
state.tokenize = inTag; | ||
return "tag"; | ||
} | ||
} else if (ch == "&") { | ||
var ok; | ||
if (stream.eat("#")) { | ||
if (stream.eat("x")) { | ||
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); | ||
} else { | ||
ok = stream.eatWhile(/[\d]/) && stream.eat(";"); | ||
} | ||
} else { | ||
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); | ||
} | ||
return ok ? "atom" : "error"; | ||
} else { | ||
stream.eatWhile(/[^&<]/); | ||
return null; | ||
} | ||
} | ||
|
||
function inTag(stream, state) { | ||
var ch = stream.next(); | ||
if (ch == ">" || (ch == "/" && stream.eat(">"))) { | ||
state.tokenize = inText; | ||
type = ch == ">" ? "endTag" : "selfcloseTag"; | ||
return "tag"; | ||
} else if (ch == "=") { | ||
type = "equals"; | ||
return null; | ||
} else if (ch == "<") { | ||
state.tokenize = inText; | ||
state.state = baseState; | ||
state.tagName = state.tagStart = null; | ||
var next = state.tokenize(stream, state); | ||
return next ? next + " error" : "error"; | ||
} else if (/[\'\"]/.test(ch)) { | ||
state.tokenize = inAttribute(ch); | ||
state.stringStartCol = stream.column(); | ||
return state.tokenize(stream, state); | ||
} else { | ||
stream.eatWhile(/[^\s\u00a0=<>\"\']/); | ||
return "word"; | ||
} | ||
} | ||
|
||
function inAttribute(quote) { | ||
var closure = function(stream, state) { | ||
while (!stream.eol()) { | ||
if (stream.next() == quote) { | ||
state.tokenize = inTag; | ||
break; | ||
} | ||
} | ||
return "string"; | ||
}; | ||
closure.isInAttribute = true; | ||
return closure; | ||
} | ||
|
||
function inBlock(style, terminator) { | ||
return function(stream, state) { | ||
while (!stream.eol()) { | ||
if (stream.match(terminator)) { | ||
state.tokenize = inText; | ||
break; | ||
} | ||
stream.next(); | ||
} | ||
return style; | ||
}; | ||
} | ||
function doctype(depth) { | ||
return function(stream, state) { | ||
var ch; | ||
while ((ch = stream.next()) != null) { | ||
if (ch == "<") { | ||
state.tokenize = doctype(depth + 1); | ||
return state.tokenize(stream, state); | ||
} else if (ch == ">") { | ||
if (depth == 1) { | ||
state.tokenize = inText; | ||
break; | ||
} else { | ||
state.tokenize = doctype(depth - 1); | ||
return state.tokenize(stream, state); | ||
} | ||
} | ||
} | ||
return "meta"; | ||
}; | ||
} | ||
|
||
function pushContext(state, tagName, startOfLine) { | ||
var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent); | ||
state.context = { | ||
prev: state.context, | ||
tagName: tagName, | ||
indent: state.indented, | ||
startOfLine: startOfLine, | ||
noIndent: noIndent | ||
}; | ||
} | ||
function popContext(state) { | ||
if (state.context) state.context = state.context.prev; | ||
} | ||
function maybePopContext(state, nextTagName) { | ||
var parentTagName; | ||
while (true) { | ||
if (!state.context) { | ||
return; | ||
} | ||
parentTagName = state.context.tagName.toLowerCase(); | ||
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || | ||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { | ||
return; | ||
} | ||
popContext(state); | ||
} | ||
} | ||
|
||
function baseState(type, stream, state) { | ||
if (type == "openTag") { | ||
state.tagName = tagName; | ||
state.tagStart = stream.column(); | ||
return attrState; | ||
} else if (type == "closeTag") { | ||
var err = false; | ||
if (state.context) { | ||
if (state.context.tagName != tagName) { | ||
if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName.toLowerCase())) | ||
popContext(state); | ||
err = !state.context || state.context.tagName != tagName; | ||
} | ||
} else { | ||
err = true; | ||
} | ||
if (err) setStyle = "error"; | ||
return err ? closeStateErr : closeState; | ||
} else { | ||
return baseState; | ||
} | ||
} | ||
function closeState(type, _stream, state) { | ||
if (type != "endTag") { | ||
setStyle = "error"; | ||
return closeState; | ||
} | ||
popContext(state); | ||
return baseState; | ||
} | ||
function closeStateErr(type, stream, state) { | ||
setStyle = "error"; | ||
return closeState(type, stream, state); | ||
} | ||
|
||
function attrState(type, stream, state) { | ||
if (type == "word") { | ||
setStyle = "attribute"; | ||
return attrEqState; | ||
} else if (type == "endTag" || type == "selfcloseTag") { | ||
var tagName = state.tagName, tagStart = state.tagStart; | ||
state.tagName = state.tagStart = null; | ||
if (type == "selfcloseTag" || | ||
Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase())) { | ||
maybePopContext(state, tagName.toLowerCase()); | ||
} else { | ||
maybePopContext(state, tagName.toLowerCase()); | ||
pushContext(state, tagName, tagStart == stream.indentation()); | ||
} | ||
return baseState; | ||
} | ||
setStyle = "error"; | ||
return attrState; | ||
} | ||
function attrEqState(type, stream, state) { | ||
if (type == "equals") return attrValueState; | ||
if (!Kludges.allowMissing) setStyle = "error"; | ||
else if (type == "word") { setStyle = "attribute"; return attrState; } | ||
return attrState(type, stream, state); | ||
} | ||
function attrValueState(type, stream, state) { | ||
if (type == "string") return attrContinuedState; | ||
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;} | ||
setStyle = "error"; | ||
return attrState(type, stream, state); | ||
} | ||
function attrContinuedState(type, stream, state) { | ||
if (type == "string") return attrContinuedState; | ||
return attrState(type, stream, state); | ||
} | ||
|
||
return { | ||
startState: function() { | ||
return {tokenize: inText, | ||
state: baseState, | ||
indented: 0, | ||
startOfLine: true, | ||
tagName: null, tagStart: null, | ||
context: null}; | ||
}, | ||
|
||
token: function(stream, state) { | ||
if (!state.tagName && stream.sol()) { | ||
state.startOfLine = true; | ||
state.indented = stream.indentation(); | ||
} | ||
if (stream.eatSpace()) return null; | ||
tagName = type = null; | ||
var style = state.tokenize(stream, state); | ||
if ((style || type) && style != "comment") { | ||
setStyle = null; | ||
state.state = state.state(type || style, stream, state); | ||
if (setStyle) | ||
style = setStyle == "error" ? style + " error" : setStyle; | ||
} | ||
state.startOfLine = false; | ||
return style; | ||
}, | ||
|
||
indent: function(state, textAfter, fullLine) { | ||
var context = state.context; | ||
// Indent multi-line strings (e.g. css). | ||
if (state.tokenize.isInAttribute) { | ||
return state.stringStartCol + 1; | ||
} | ||
if ((state.tokenize != inTag && state.tokenize != inText) || | ||
context && context.noIndent) | ||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; | ||
// Indent the starts of attribute names. | ||
if (state.tagName) { | ||
if (multilineTagIndentPastTag) | ||
return state.tagStart + state.tagName.length + 2; | ||
else | ||
return state.tagStart + indentUnit * multilineTagIndentFactor; | ||
} | ||
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0; | ||
if (context && /^<\//.test(textAfter)) | ||
context = context.prev; | ||
while (context && !context.startOfLine) | ||
context = context.prev; | ||
if (context) return context.indent + indentUnit; | ||
else return 0; | ||
}, | ||
|
||
electricChars: "/", | ||
blockCommentStart: "<!--", | ||
blockCommentEnd: "-->", | ||
|
||
configuration: parserConfig.htmlMode ? "html" : "xml", | ||
helperType: parserConfig.htmlMode ? "html" : "xml" | ||
}; | ||
}); | ||
|
||
CodeMirror.defineMIME("text/xml", "xml"); | ||
CodeMirror.defineMIME("application/xml", "xml"); | ||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) | ||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,361 @@ | ||
CodeMirror.defineMode("javascript", function(config, parserConfig) { | ||
var indentUnit = config.indentUnit; | ||
var jsonMode = parserConfig.json; | ||
|
||
// Tokenizer | ||
|
||
var keywords = function(){ | ||
function kw(type) {return {type: type, style: "keyword"};} | ||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); | ||
var operator = kw("operator"), atom = {type: "atom", style: "atom"}; | ||
return { | ||
"if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, | ||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, | ||
"var": kw("var"), "const": kw("var"), "let": kw("var"), | ||
"function": kw("function"), "catch": kw("catch"), | ||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), | ||
"in": operator, "typeof": operator, "instanceof": operator, | ||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom | ||
}; | ||
}(); | ||
|
||
var isOperatorChar = /[+\-*&%=<>!?|]/; | ||
|
||
function chain(stream, state, f) { | ||
state.tokenize = f; | ||
return f(stream, state); | ||
} | ||
|
||
function nextUntilUnescaped(stream, end) { | ||
var escaped = false, next; | ||
while ((next = stream.next()) != null) { | ||
if (next == end && !escaped) | ||
return false; | ||
escaped = !escaped && next == "\\"; | ||
} | ||
return escaped; | ||
} | ||
|
||
// Used as scratch variables to communicate multiple values without | ||
// consing up tons of objects. | ||
var type, content; | ||
function ret(tp, style, cont) { | ||
type = tp; content = cont; | ||
return style; | ||
} | ||
|
||
function jsTokenBase(stream, state) { | ||
var ch = stream.next(); | ||
if (ch == '"' || ch == "'") | ||
return chain(stream, state, jsTokenString(ch)); | ||
else if (/[\[\]{}\(\),;\:\.]/.test(ch)) | ||
return ret(ch); | ||
else if (ch == "0" && stream.eat(/x/i)) { | ||
stream.eatWhile(/[\da-f]/i); | ||
return ret("number", "number"); | ||
} | ||
else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { | ||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); | ||
return ret("number", "number"); | ||
} | ||
else if (ch == "/") { | ||
if (stream.eat("*")) { | ||
return chain(stream, state, jsTokenComment); | ||
} | ||
else if (stream.eat("/")) { | ||
stream.skipToEnd(); | ||
return ret("comment", "comment"); | ||
} | ||
else if (state.reAllowed) { | ||
nextUntilUnescaped(stream, "/"); | ||
stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla | ||
return ret("regexp", "string-2"); | ||
} | ||
else { | ||
stream.eatWhile(isOperatorChar); | ||
return ret("operator", null, stream.current()); | ||
} | ||
} | ||
else if (ch == "#") { | ||
stream.skipToEnd(); | ||
return ret("error", "error"); | ||
} | ||
else if (isOperatorChar.test(ch)) { | ||
stream.eatWhile(isOperatorChar); | ||
return ret("operator", null, stream.current()); | ||
} | ||
else { | ||
stream.eatWhile(/[\w\$_]/); | ||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; | ||
return (known && state.kwAllowed) ? ret(known.type, known.style, word) : | ||
ret("variable", "variable", word); | ||
} | ||
} | ||
|
||
function jsTokenString(quote) { | ||
return function(stream, state) { | ||
if (!nextUntilUnescaped(stream, quote)) | ||
state.tokenize = jsTokenBase; | ||
return ret("string", "string"); | ||
}; | ||
} | ||
|
||
function jsTokenComment(stream, state) { | ||
var maybeEnd = false, ch; | ||
while (ch = stream.next()) { | ||
if (ch == "/" && maybeEnd) { | ||
state.tokenize = jsTokenBase; | ||
break; | ||
} | ||
maybeEnd = (ch == "*"); | ||
} | ||
return ret("comment", "comment"); | ||
} | ||
|
||
// Parser | ||
|
||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true}; | ||
|
||
function JSLexical(indented, column, type, align, prev, info) { | ||
this.indented = indented; | ||
this.column = column; | ||
this.type = type; | ||
this.prev = prev; | ||
this.info = info; | ||
if (align != null) this.align = align; | ||
} | ||
|
||
function inScope(state, varname) { | ||
for (var v = state.localVars; v; v = v.next) | ||
if (v.name == varname) return true; | ||
} | ||
|
||
function parseJS(state, style, type, content, stream) { | ||
var cc = state.cc; | ||
// Communicate our context to the combinators. | ||
// (Less wasteful than consing up a hundred closures on every call.) | ||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; | ||
|
||
if (!state.lexical.hasOwnProperty("align")) | ||
state.lexical.align = true; | ||
|
||
while(true) { | ||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; | ||
if (combinator(type, content)) { | ||
while(cc.length && cc[cc.length - 1].lex) | ||
cc.pop()(); | ||
if (cx.marked) return cx.marked; | ||
if (type == "variable" && inScope(state, content)) return "variable-2"; | ||
return style; | ||
} | ||
} | ||
} | ||
|
||
// Combinator utils | ||
|
||
var cx = {state: null, column: null, marked: null, cc: null}; | ||
function pass() { | ||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); | ||
} | ||
function cont() { | ||
pass.apply(null, arguments); | ||
return true; | ||
} | ||
function register(varname) { | ||
var state = cx.state; | ||
if (state.context) { | ||
cx.marked = "def"; | ||
for (var v = state.localVars; v; v = v.next) | ||
if (v.name == varname) return; | ||
state.localVars = {name: varname, next: state.localVars}; | ||
} | ||
} | ||
|
||
// Combinators | ||
|
||
var defaultVars = {name: "this", next: {name: "arguments"}}; | ||
function pushcontext() { | ||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; | ||
cx.state.localVars = defaultVars; | ||
} | ||
function popcontext() { | ||
cx.state.localVars = cx.state.context.vars; | ||
cx.state.context = cx.state.context.prev; | ||
} | ||
function pushlex(type, info) { | ||
var result = function() { | ||
var state = cx.state; | ||
state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info); | ||
}; | ||
result.lex = true; | ||
return result; | ||
} | ||
function poplex() { | ||
var state = cx.state; | ||
if (state.lexical.prev) { | ||
if (state.lexical.type == ")") | ||
state.indented = state.lexical.indented; | ||
state.lexical = state.lexical.prev; | ||
} | ||
} | ||
poplex.lex = true; | ||
|
||
function expect(wanted) { | ||
return function expecting(type) { | ||
if (type == wanted) return cont(); | ||
else if (wanted == ";") return pass(); | ||
else return cont(arguments.callee); | ||
}; | ||
} | ||
|
||
function statement(type) { | ||
if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex); | ||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); | ||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex); | ||
if (type == "{") return cont(pushlex("}"), block, poplex); | ||
if (type == ";") return cont(); | ||
if (type == "function") return cont(functiondef); | ||
if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), | ||
poplex, statement, poplex); | ||
if (type == "variable") return cont(pushlex("stat"), maybelabel); | ||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), | ||
block, poplex, poplex); | ||
if (type == "case") return cont(expression, expect(":")); | ||
if (type == "default") return cont(expect(":")); | ||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), | ||
statement, poplex, popcontext); | ||
return pass(pushlex("stat"), expression, expect(";"), poplex); | ||
} | ||
function expression(type) { | ||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator); | ||
if (type == "function") return cont(functiondef); | ||
if (type == "keyword c") return cont(maybeexpression); | ||
if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator); | ||
if (type == "operator") return cont(expression); | ||
if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator); | ||
if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator); | ||
return cont(); | ||
} | ||
function maybeexpression(type) { | ||
if (type.match(/[;\}\)\],]/)) return pass(); | ||
return pass(expression); | ||
} | ||
|
||
function maybeoperator(type, value) { | ||
if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator); | ||
if (type == "operator" && value == "?") return cont(expression, expect(":"), expression); | ||
if (type == ";") return; | ||
if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator); | ||
if (type == ".") return cont(property, maybeoperator); | ||
if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator); | ||
} | ||
function maybelabel(type) { | ||
if (type == ":") return cont(poplex, statement); | ||
return pass(maybeoperator, expect(";"), poplex); | ||
} | ||
function property(type) { | ||
if (type == "variable") {cx.marked = "property"; return cont();} | ||
} | ||
function objprop(type) { | ||
if (type == "variable") cx.marked = "property"; | ||
if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression); | ||
} | ||
function commasep(what, end) { | ||
function proceed(type) { | ||
if (type == ",") return cont(what, proceed); | ||
if (type == end) return cont(); | ||
return cont(expect(end)); | ||
} | ||
return function commaSeparated(type) { | ||
if (type == end) return cont(); | ||
else return pass(what, proceed); | ||
}; | ||
} | ||
function block(type) { | ||
if (type == "}") return cont(); | ||
return pass(statement, block); | ||
} | ||
function vardef1(type, value) { | ||
if (type == "variable"){register(value); return cont(vardef2);} | ||
return cont(); | ||
} | ||
function vardef2(type, value) { | ||
if (value == "=") return cont(expression, vardef2); | ||
if (type == ",") return cont(vardef1); | ||
} | ||
function forspec1(type) { | ||
if (type == "var") return cont(vardef1, forspec2); | ||
if (type == ";") return pass(forspec2); | ||
if (type == "variable") return cont(formaybein); | ||
return pass(forspec2); | ||
} | ||
function formaybein(type, value) { | ||
if (value == "in") return cont(expression); | ||
return cont(maybeoperator, forspec2); | ||
} | ||
function forspec2(type, value) { | ||
if (type == ";") return cont(forspec3); | ||
if (value == "in") return cont(expression); | ||
return cont(expression, expect(";"), forspec3); | ||
} | ||
function forspec3(type) { | ||
if (type != ")") cont(expression); | ||
} | ||
function functiondef(type, value) { | ||
if (type == "variable") {register(value); return cont(functiondef);} | ||
if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext); | ||
} | ||
function funarg(type, value) { | ||
if (type == "variable") {register(value); return cont();} | ||
} | ||
|
||
// Interface | ||
|
||
return { | ||
startState: function(basecolumn) { | ||
return { | ||
tokenize: jsTokenBase, | ||
reAllowed: true, | ||
kwAllowed: true, | ||
cc: [], | ||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), | ||
localVars: parserConfig.localVars, | ||
context: parserConfig.localVars && {vars: parserConfig.localVars}, | ||
indented: 0 | ||
}; | ||
}, | ||
|
||
token: function(stream, state) { | ||
if (stream.sol()) { | ||
if (!state.lexical.hasOwnProperty("align")) | ||
state.lexical.align = false; | ||
state.indented = stream.indentation(); | ||
} | ||
if (stream.eatSpace()) return null; | ||
var style = state.tokenize(stream, state); | ||
if (type == "comment") return style; | ||
state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/)); | ||
state.kwAllowed = type != '.'; | ||
return parseJS(state, style, type, content, stream); | ||
}, | ||
|
||
indent: function(state, textAfter) { | ||
if (state.tokenize != jsTokenBase) return 0; | ||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; | ||
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; | ||
var type = lexical.type, closing = firstChar == type; | ||
if (type == "vardef") return lexical.indented + 4; | ||
else if (type == "form" && firstChar == "{") return lexical.indented; | ||
else if (type == "stat" || type == "form") return lexical.indented + indentUnit; | ||
else if (lexical.info == "switch" && !closing) | ||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); | ||
else if (lexical.align) return lexical.column + (closing ? 0 : 1); | ||
else return lexical.indented + (closing ? 0 : indentUnit); | ||
}, | ||
|
||
electricChars: ":{}" | ||
}; | ||
}); | ||
|
||
CodeMirror.defineMIME("text/javascript", "javascript"); | ||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
CodeMirror.defineMode("ruby", function(config, parserConfig) { | ||
function wordObj(words) { | ||
var o = {}; | ||
for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; | ||
return o; | ||
} | ||
var keywords = wordObj([ | ||
"alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else", | ||
"elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", | ||
"redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", | ||
"until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc", | ||
"caller", "lambda", "proc", "public", "protected", "private", "require", "load", | ||
"require_relative", "extend", "autoload" | ||
]); | ||
var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then", | ||
"catch", "loop", "proc", "begin"]); | ||
var dedentWords = wordObj(["end", "until"]); | ||
var matching = {"[": "]", "{": "}", "(": ")"}; | ||
var curPunc; | ||
|
||
function chain(newtok, stream, state) { | ||
state.tokenize.push(newtok); | ||
return newtok(stream, state); | ||
} | ||
|
||
function tokenBase(stream, state) { | ||
curPunc = null; | ||
if (stream.sol() && stream.match("=begin") && stream.eol()) { | ||
state.tokenize.push(readBlockComment); | ||
return "comment"; | ||
} | ||
if (stream.eatSpace()) return null; | ||
var ch = stream.next(), m; | ||
if (ch == "`" || ch == "'" || ch == '"' || | ||
(ch == "/" && !stream.eol() && stream.peek() != " ")) { | ||
return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state); | ||
} else if (ch == "%") { | ||
var style, embed = false; | ||
if (stream.eat("s")) style = "atom"; | ||
else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; } | ||
else if (stream.eat(/[wxqr]/)) style = "string"; | ||
var delim = stream.eat(/[^\w\s]/); | ||
if (!delim) return "operator"; | ||
if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; | ||
return chain(readQuoted(delim, style, embed, true), stream, state); | ||
} else if (ch == "#") { | ||
stream.skipToEnd(); | ||
return "comment"; | ||
} else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) { | ||
return chain(readHereDoc(m[1]), stream, state); | ||
} else if (ch == "0") { | ||
if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/); | ||
else if (stream.eat("b")) stream.eatWhile(/[01]/); | ||
else stream.eatWhile(/[0-7]/); | ||
return "number"; | ||
} else if (/\d/.test(ch)) { | ||
stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/); | ||
return "number"; | ||
} else if (ch == "?") { | ||
while (stream.match(/^\\[CM]-/)) {} | ||
if (stream.eat("\\")) stream.eatWhile(/\w/); | ||
else stream.next(); | ||
return "string"; | ||
} else if (ch == ":") { | ||
if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state); | ||
if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state); | ||
stream.eatWhile(/[\w\?]/); | ||
return "atom"; | ||
} else if (ch == "@") { | ||
stream.eat("@"); | ||
stream.eatWhile(/[\w\?]/); | ||
return "variable-2"; | ||
} else if (ch == "$") { | ||
stream.next(); | ||
stream.eatWhile(/[\w\?]/); | ||
return "variable-3"; | ||
} else if (/\w/.test(ch)) { | ||
stream.eatWhile(/[\w\?]/); | ||
if (stream.eat(":")) return "atom"; | ||
return "ident"; | ||
} else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) { | ||
curPunc = "|"; | ||
return null; | ||
} else if (/[\(\)\[\]{}\\;]/.test(ch)) { | ||
curPunc = ch; | ||
return null; | ||
} else if (ch == "-" && stream.eat(">")) { | ||
return "arrow"; | ||
} else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) { | ||
stream.eatWhile(/[=+\-\/*:\.^%<>~|]/); | ||
return "operator"; | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
function tokenBaseUntilBrace() { | ||
var depth = 1; | ||
return function(stream, state) { | ||
if (stream.peek() == "}") { | ||
depth--; | ||
if (depth == 0) { | ||
state.tokenize.pop(); | ||
return state.tokenize[state.tokenize.length-1](stream, state); | ||
} | ||
} else if (stream.peek() == "{") { | ||
depth++; | ||
} | ||
return tokenBase(stream, state); | ||
}; | ||
} | ||
function readQuoted(quote, style, embed, unescaped) { | ||
return function(stream, state) { | ||
var escaped = false, ch; | ||
while ((ch = stream.next()) != null) { | ||
if (ch == quote && (unescaped || !escaped)) { | ||
state.tokenize.pop(); | ||
break; | ||
} | ||
if (embed && ch == "#" && !escaped && stream.eat("{")) { | ||
state.tokenize.push(tokenBaseUntilBrace(arguments.callee)); | ||
break; | ||
} | ||
escaped = !escaped && ch == "\\"; | ||
} | ||
return style; | ||
}; | ||
} | ||
function readHereDoc(phrase) { | ||
return function(stream, state) { | ||
if (stream.match(phrase)) state.tokenize.pop(); | ||
else stream.skipToEnd(); | ||
return "string"; | ||
}; | ||
} | ||
function readBlockComment(stream, state) { | ||
if (stream.sol() && stream.match("=end") && stream.eol()) | ||
state.tokenize.pop(); | ||
stream.skipToEnd(); | ||
return "comment"; | ||
} | ||
|
||
return { | ||
startState: function() { | ||
return {tokenize: [tokenBase], | ||
indented: 0, | ||
context: {type: "top", indented: -config.indentUnit}, | ||
continuedLine: false, | ||
lastTok: null, | ||
varList: false}; | ||
}, | ||
|
||
token: function(stream, state) { | ||
if (stream.sol()) state.indented = stream.indentation(); | ||
var style = state.tokenize[state.tokenize.length-1](stream, state), kwtype; | ||
if (style == "ident") { | ||
var word = stream.current(); | ||
style = keywords.propertyIsEnumerable(stream.current()) ? "keyword" | ||
: /^[A-Z]/.test(word) ? "tag" | ||
: (state.lastTok == "def" || state.lastTok == "class" || state.varList) ? "def" | ||
: "variable"; | ||
if (indentWords.propertyIsEnumerable(word)) kwtype = "indent"; | ||
else if (dedentWords.propertyIsEnumerable(word)) kwtype = "dedent"; | ||
else if ((word == "if" || word == "unless") && stream.column() == stream.indentation()) | ||
kwtype = "indent"; | ||
} | ||
if (curPunc || (style && style != "comment")) state.lastTok = word || curPunc || style; | ||
if (curPunc == "|") state.varList = !state.varList; | ||
|
||
if (kwtype == "indent" || /[\(\[\{]/.test(curPunc)) | ||
state.context = {prev: state.context, type: curPunc || style, indented: state.indented}; | ||
else if ((kwtype == "dedent" || /[\)\]\}]/.test(curPunc)) && state.context.prev) | ||
state.context = state.context.prev; | ||
|
||
if (stream.eol()) | ||
state.continuedLine = (curPunc == "\\" || style == "operator"); | ||
return style; | ||
}, | ||
|
||
indent: function(state, textAfter) { | ||
if (state.tokenize[state.tokenize.length-1] != tokenBase) return 0; | ||
var firstChar = textAfter && textAfter.charAt(0); | ||
var ct = state.context; | ||
var closing = ct.type == matching[firstChar] || | ||
ct.type == "keyword" && /^(?:end|until|else|elsif|when|rescue)\b/.test(textAfter); | ||
return ct.indented + (closing ? 0 : config.indentUnit) + | ||
(state.continuedLine ? config.indentUnit : 0); | ||
}, | ||
electricChars: "}de" // enD and rescuE | ||
|
||
}; | ||
}); | ||
|
||
CodeMirror.defineMIME("text/x-ruby", "ruby"); |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
require 'opal' | ||
require 'opal-parser' | ||
|
||
require '_vendor/jquery' | ||
require '_vendor/bootstrap' | ||
require 'opal-jquery' | ||
|
||
require '_vendor/codemirror' | ||
require '_vendor/codemirror-html' | ||
require '_vendor/codemirror-css' | ||
require '_vendor/codemirror-ruby' | ||
|
||
module Playground | ||
class Editor | ||
OPTIONS = { lineNumbers: true, theme: 'solarized light' } | ||
|
||
def initialize(dom_id, options) | ||
options = OPTIONS.merge(options).to_n | ||
@native = `CodeMirror(document.getElementById(dom_id), #{options})` | ||
end | ||
|
||
def value=(str) | ||
`#@native.setValue(str)` | ||
end | ||
|
||
def value | ||
`#@native.getValue()` | ||
end | ||
end | ||
|
||
class Runner | ||
def initialize | ||
@html = create_editor(:html_pane, mode: 'xml') | ||
@ruby = create_editor(:ruby_pane, mode: 'ruby') | ||
@css = create_editor(:css_pane, mode: 'css') | ||
@result = Element['#result-frame'] | ||
|
||
@html.value = HTML | ||
@ruby.value = RUBY | ||
@css.value = CSS | ||
|
||
Element.find('#run-code').on(:click) { run_code } | ||
|
||
run_code | ||
end | ||
|
||
def create_editor(id, opts) | ||
opts = { lineNumbers: true, | ||
theme: 'solarized light', | ||
extraKeys: { | ||
'Cmd-Enter' => proc { run_code } | ||
} | ||
}.merge(opts) | ||
|
||
Editor.new(id, opts) | ||
end | ||
|
||
def run_code | ||
html, css, ruby = @html.value, @css.value, @ruby.value | ||
javascript = Opal.compile ruby | ||
|
||
update_iframe(<<-HTML) | ||
<html> | ||
<head> | ||
<style>#{css}</style> | ||
</head> | ||
<body> | ||
#{html} | ||
<script src="/javascripts/result_boot.js"></script> | ||
<script> | ||
#{javascript} | ||
</script> | ||
</body> | ||
</html> | ||
HTML | ||
end | ||
|
||
def update_iframe(html) | ||
%x{ | ||
var iframe = #@result[0], doc; | ||
if (iframe.contentDocument) { | ||
doc = iframe.contentDocument; | ||
} else if (iframe.contentWindow) { | ||
doc = iframe.contentWindow.document; | ||
} else { | ||
doc = iframe.document; | ||
} | ||
doc.open() | ||
doc.writeln(#{html}); | ||
doc.close(); | ||
} | ||
end | ||
end | ||
|
||
HTML = <<-HTML | ||
<button id="main"> | ||
Click me | ||
</button> | ||
HTML | ||
|
||
CSS = <<-CSS | ||
body { | ||
background: #eeeeee; | ||
} | ||
CSS | ||
|
||
RUBY = <<-RUBY | ||
Document.ready? do | ||
Element.find('#main').on(:click) do | ||
alert "Hello, World!" | ||
end | ||
end | ||
RUBY | ||
end | ||
|
||
Document.ready? do | ||
Playground::Runner.new | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
require '_vendor/jquery' | ||
require 'opal' | ||
require 'opal-jquery' |
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
/* BASICS */ | ||
|
||
.CodeMirror { | ||
/* Set height, width, borders, and global font properties here */ | ||
font-family: monospace; | ||
height: 300px; | ||
} | ||
.CodeMirror-scroll { | ||
/* Set scrolling behaviour here */ | ||
overflow: auto; | ||
} | ||
|
||
/* PADDING */ | ||
|
||
.CodeMirror-lines { | ||
padding: 4px 0; /* Vertical padding around content */ | ||
} | ||
.CodeMirror pre { | ||
padding: 0 4px; /* Horizontal padding of content */ | ||
} | ||
|
||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { | ||
background-color: white; /* The little square between H and V scrollbars */ | ||
} | ||
|
||
/* GUTTER */ | ||
|
||
.CodeMirror-gutters { | ||
border-right: 1px solid #ddd; | ||
background-color: #f7f7f7; | ||
white-space: nowrap; | ||
} | ||
.CodeMirror-linenumbers {} | ||
.CodeMirror-linenumber { | ||
padding: 0 3px 0 5px; | ||
min-width: 20px; | ||
text-align: right; | ||
color: #999; | ||
} | ||
|
||
/* CURSOR */ | ||
|
||
.CodeMirror div.CodeMirror-cursor { | ||
border-left: 1px solid black; | ||
z-index: 3; | ||
} | ||
/* Shown when moving in bi-directional text */ | ||
.CodeMirror div.CodeMirror-secondarycursor { | ||
border-left: 1px solid silver; | ||
} | ||
.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { | ||
width: auto; | ||
border: 0; | ||
background: #7e7; | ||
z-index: 1; | ||
} | ||
/* Can style cursor different in overwrite (non-insert) mode */ | ||
.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} | ||
|
||
.cm-tab { display: inline-block; } | ||
|
||
/* DEFAULT THEME */ | ||
|
||
.cm-s-default .cm-keyword {color: #708;} | ||
.cm-s-default .cm-atom {color: #219;} | ||
.cm-s-default .cm-number {color: #164;} | ||
.cm-s-default .cm-def {color: #00f;} | ||
.cm-s-default .cm-variable {color: black;} | ||
.cm-s-default .cm-variable-2 {color: #05a;} | ||
.cm-s-default .cm-variable-3 {color: #085;} | ||
.cm-s-default .cm-property {color: black;} | ||
.cm-s-default .cm-operator {color: black;} | ||
.cm-s-default .cm-comment {color: #a50;} | ||
.cm-s-default .cm-string {color: #a11;} | ||
.cm-s-default .cm-string-2 {color: #f50;} | ||
.cm-s-default .cm-meta {color: #555;} | ||
.cm-s-default .cm-qualifier {color: #555;} | ||
.cm-s-default .cm-builtin {color: #30a;} | ||
.cm-s-default .cm-bracket {color: #997;} | ||
.cm-s-default .cm-tag {color: #170;} | ||
.cm-s-default .cm-attribute {color: #00c;} | ||
.cm-s-default .cm-header {color: blue;} | ||
.cm-s-default .cm-quote {color: #090;} | ||
.cm-s-default .cm-hr {color: #999;} | ||
.cm-s-default .cm-link {color: #00c;} | ||
|
||
.cm-negative {color: #d44;} | ||
.cm-positive {color: #292;} | ||
.cm-header, .cm-strong {font-weight: bold;} | ||
.cm-em {font-style: italic;} | ||
.cm-link {text-decoration: underline;} | ||
|
||
.cm-s-default .cm-error {color: #f00;} | ||
.cm-invalidchar {color: #f00;} | ||
|
||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} | ||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} | ||
.CodeMirror-activeline-background {background: #e8f2ff;} | ||
|
||
/* STOP */ | ||
|
||
/* The rest of this file contains styles related to the mechanics of | ||
the editor. You probably shouldn't touch them. */ | ||
|
||
.CodeMirror { | ||
line-height: 1; | ||
position: relative; | ||
overflow: hidden; | ||
background: white; | ||
color: black; | ||
} | ||
|
||
.CodeMirror-scroll { | ||
/* 30px is the magic margin used to hide the element's real scrollbars */ | ||
/* See overflow: hidden in .CodeMirror */ | ||
margin-bottom: -30px; margin-right: -30px; | ||
padding-bottom: 30px; padding-right: 30px; | ||
height: 100%; | ||
outline: none; /* Prevent dragging from highlighting the element */ | ||
position: relative; | ||
-moz-box-sizing: content-box; | ||
box-sizing: content-box; | ||
} | ||
.CodeMirror-sizer { | ||
position: relative; | ||
} | ||
|
||
/* The fake, visible scrollbars. Used to force redraw during scrolling | ||
before actuall scrolling happens, thus preventing shaking and | ||
flickering artifacts. */ | ||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { | ||
position: absolute; | ||
z-index: 6; | ||
display: none; | ||
} | ||
.CodeMirror-vscrollbar { | ||
right: 0; top: 0; | ||
overflow-x: hidden; | ||
overflow-y: scroll; | ||
} | ||
.CodeMirror-hscrollbar { | ||
bottom: 0; left: 0; | ||
overflow-y: hidden; | ||
overflow-x: scroll; | ||
} | ||
.CodeMirror-scrollbar-filler { | ||
right: 0; bottom: 0; | ||
} | ||
.CodeMirror-gutter-filler { | ||
left: 0; bottom: 0; | ||
} | ||
|
||
.CodeMirror-gutters { | ||
position: absolute; left: 0; top: 0; | ||
padding-bottom: 30px; | ||
z-index: 3; | ||
} | ||
.CodeMirror-gutter { | ||
white-space: normal; | ||
height: 100%; | ||
-moz-box-sizing: content-box; | ||
box-sizing: content-box; | ||
padding-bottom: 30px; | ||
margin-bottom: -32px; | ||
display: inline-block; | ||
/* Hack to make IE7 behave */ | ||
*zoom:1; | ||
*display:inline; | ||
} | ||
.CodeMirror-gutter-elt { | ||
position: absolute; | ||
cursor: default; | ||
z-index: 4; | ||
} | ||
|
||
.CodeMirror-lines { | ||
cursor: text; | ||
} | ||
.CodeMirror pre { | ||
/* Reset some styles that the rest of the page might have set */ | ||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; | ||
border-width: 0; | ||
background: transparent; | ||
font-family: inherit; | ||
font-size: inherit; | ||
margin: 0; | ||
white-space: pre; | ||
word-wrap: normal; | ||
line-height: inherit; | ||
color: inherit; | ||
z-index: 2; | ||
position: relative; | ||
overflow: visible; | ||
} | ||
.CodeMirror-wrap pre { | ||
word-wrap: break-word; | ||
white-space: pre-wrap; | ||
word-break: normal; | ||
} | ||
.CodeMirror-code pre { | ||
border-right: 30px solid transparent; | ||
width: -webkit-fit-content; | ||
width: -moz-fit-content; | ||
width: fit-content; | ||
} | ||
.CodeMirror-wrap .CodeMirror-code pre { | ||
border-right: none; | ||
width: auto; | ||
} | ||
.CodeMirror-linebackground { | ||
position: absolute; | ||
left: 0; right: 0; top: 0; bottom: 0; | ||
z-index: 0; | ||
} | ||
|
||
.CodeMirror-linewidget { | ||
position: relative; | ||
z-index: 2; | ||
overflow: auto; | ||
} | ||
|
||
.CodeMirror-widget {} | ||
|
||
.CodeMirror-wrap .CodeMirror-scroll { | ||
overflow-x: hidden; | ||
} | ||
|
||
.CodeMirror-measure { | ||
position: absolute; | ||
width: 100%; | ||
height: 0; | ||
overflow: hidden; | ||
visibility: hidden; | ||
} | ||
.CodeMirror-measure pre { position: static; } | ||
|
||
.CodeMirror div.CodeMirror-cursor { | ||
position: absolute; | ||
visibility: hidden; | ||
border-right: none; | ||
width: 0; | ||
} | ||
.CodeMirror-focused div.CodeMirror-cursor { | ||
visibility: visible; | ||
} | ||
|
||
.CodeMirror-selected { background: #d9d9d9; } | ||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } | ||
|
||
.cm-searching { | ||
background: #ffa; | ||
background: rgba(255, 255, 0, .4); | ||
} | ||
|
||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */ | ||
.CodeMirror span { *vertical-align: text-bottom; } | ||
|
||
@media print { | ||
/* Hide the cursor when printing */ | ||
.CodeMirror div.CodeMirror-cursor { | ||
visibility: hidden; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
//= require _vendor/bootstrap.min | ||
//= require _vendor/codemirror | ||
//= require _vendor/codemirror-solarized |