mirror of
https://github.com/jsbin/jsbin.git
synced 2026-01-18 15:18:04 +00:00
Mass check in of JS Bin 2.8 - lots of UI changes - in complete though - IE to test.
This commit is contained in:
parent
a6a63e086f
commit
1ddb2a0360
2
Makefile
2
Makefile
@ -1,2 +1,4 @@
|
||||
all:
|
||||
git submodule init
|
||||
git submodule update
|
||||
php ./build/build.php
|
||||
|
||||
38
app.php
38
app.php
@ -76,7 +76,10 @@ if (!$action) {
|
||||
}
|
||||
|
||||
$sql = sprintf('insert into sandbox (javascript, html, created, last_viewed, url, revision) values ("%s", "%s", now(), now(), "%s", "%s")', mysql_real_escape_string($javascript), mysql_real_escape_string($html), mysql_real_escape_string($code_id), mysql_real_escape_string($revision));
|
||||
mysql_query($sql);
|
||||
$ok = mysql_query($sql);
|
||||
|
||||
// error_log('saved: ' . $code_id . ' - ' . $revision . ' -- ' . $ok . ' ' . strlen($sql));
|
||||
// error_log(mysql_error());
|
||||
}
|
||||
|
||||
if (stripos($method, 'download') !== false) {
|
||||
@ -190,17 +193,6 @@ function encode($s) {
|
||||
return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $s) . '"';
|
||||
}
|
||||
|
||||
// returns the app loaded with json html + js content
|
||||
function edit() {
|
||||
|
||||
}
|
||||
|
||||
// saves current state - should I store regardless of content, to start their own
|
||||
// milestones?
|
||||
function save() {
|
||||
|
||||
}
|
||||
|
||||
function getCodeIdParams($request) {
|
||||
$revision = array_pop($request);
|
||||
$code_id = array_pop($request);
|
||||
@ -271,8 +263,16 @@ function getCode($code_id, $revision, $testonly = false) {
|
||||
function defaultCode($not_found = false) {
|
||||
$library = '';
|
||||
|
||||
if (@$_GET['html']) {
|
||||
$html = $_GET['html'];
|
||||
$usingRequest = false;
|
||||
|
||||
if (isset($_REQUEST['html']) || isset($_REQUEST['js'])) {
|
||||
$usingRequest = true;
|
||||
}
|
||||
|
||||
if (@$_REQUEST['html']) {
|
||||
$html = $_REQUEST['html'];
|
||||
} else if ($usingRequest) {
|
||||
$html = '';
|
||||
} else {
|
||||
$html = <<<HERE_DOC
|
||||
<!DOCTYPE html>
|
||||
@ -297,14 +297,16 @@ HERE_DOC;
|
||||
|
||||
$javascript = '';
|
||||
|
||||
if (!@$_GET['js']) {
|
||||
if (@$_REQUEST['js']) {
|
||||
$javascript = $_REQUEST['js'];
|
||||
} else if ($usingRequest) {
|
||||
$javascript = '';
|
||||
} else {
|
||||
if ($not_found) {
|
||||
$javascript = 'document.getElementById("hello").innerHTML = "<strong>This URL does not have any code saved to it.</strong>";';
|
||||
} else {
|
||||
$javascript = "if (document.getElementById('hello')) {\n document.getElementById('hello').innerHTML = 'Hello World - this was inserted using JavaScript';\n}\n";
|
||||
}
|
||||
} else {
|
||||
$javascript = $_GET['js'];
|
||||
}
|
||||
}
|
||||
|
||||
return array(get_magic_quotes_gpc() ? stripslashes($html) : $html, get_magic_quotes_gpc() ? stripslashes($javascript) : $javascript);
|
||||
|
||||
377
css/style.css
377
css/style.css
@ -17,7 +17,7 @@ body {
|
||||
font-size: 13px;
|
||||
min-width: 976px;
|
||||
overflow: hidden;
|
||||
background: url(/images/jsbin-bg.gif) repeat-x top left;
|
||||
background: url(/images/jsbin-bg.gif) repeat-x 0 -10px;
|
||||
}
|
||||
|
||||
p {
|
||||
@ -25,23 +25,32 @@ p {
|
||||
}
|
||||
|
||||
#control {
|
||||
height: 61px;
|
||||
overflow: hidden;
|
||||
height: 51px;
|
||||
position: absolute;
|
||||
/* width: 100%;*/
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#control, .label {
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.control, .help, .starting {
|
||||
width: 100px;
|
||||
padding: 15px;
|
||||
/* width: 100px;*/
|
||||
padding: 13px 10px;
|
||||
float: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.control {
|
||||
padding-right: 0;
|
||||
width: 50%;
|
||||
/* width: 50%;*/
|
||||
}
|
||||
|
||||
.starting {
|
||||
@ -49,7 +58,7 @@ p {
|
||||
}
|
||||
|
||||
.help {
|
||||
width: 40%;
|
||||
width: 10%;
|
||||
text-align: right;
|
||||
float: right;
|
||||
}
|
||||
@ -59,7 +68,7 @@ p {
|
||||
}
|
||||
|
||||
.starting, .help {
|
||||
line-height: 32px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
ul.flat {
|
||||
@ -106,8 +115,9 @@ a:hover {
|
||||
}
|
||||
|
||||
#bin {
|
||||
top: 62px;
|
||||
top: 52px;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
div.html {
|
||||
@ -128,8 +138,13 @@ div.html {
|
||||
border: 0;
|
||||
}
|
||||
*/
|
||||
div.code {
|
||||
width: 50%;
|
||||
div.code, #live, .resize {
|
||||
/* width: 50%;*/
|
||||
/* -webkit-transition: left ease-out 100ms, right ease-out 100ms;*/
|
||||
}
|
||||
|
||||
.resize {
|
||||
background: #ccc url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAMCAYAAACnfgdqAAAAMElEQVQIHWP8//8/AxRoMAA5ZkDcAsT/mYCiN4GYBYidGIECUFUMDCAZOEDmUNkAAKKgK80+TE8oAAAAAElFTkSuQmCC) no-repeat left 45%;
|
||||
}
|
||||
|
||||
div.preview {
|
||||
@ -149,7 +164,7 @@ div.preview {
|
||||
.code .label p {
|
||||
/* display: inline;*/
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
/* cursor: pointer;*/
|
||||
}
|
||||
|
||||
.code .label label {
|
||||
@ -173,6 +188,10 @@ div.preview {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.javascript {
|
||||
right: 50%;
|
||||
}
|
||||
|
||||
iframe.javascript {
|
||||
border-right: 1px solid #ccc !important;
|
||||
}
|
||||
@ -183,14 +202,14 @@ iframe.javascript {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
a.button {
|
||||
.button {
|
||||
border: 1px solid #ccc;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
height: 12px;
|
||||
line-height: 12px;
|
||||
padding: 10px;
|
||||
padding: 6px 10px;
|
||||
display: block;
|
||||
float: left;
|
||||
text-decoration: none;
|
||||
@ -199,19 +218,30 @@ a.button {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
a.gap {
|
||||
#control span {
|
||||
display: block;
|
||||
float: left;
|
||||
height: 10px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 10px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.gap {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
a.button:hover {
|
||||
-moz-box-shadow: #fff 0px 0px 5px;
|
||||
-webkit-box-shadow: #fff 0px 0px 5px;
|
||||
box-shadow: #fff 0px 0px 5px;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.button:active, .button:focus {
|
||||
a.button:active, .button:focus {
|
||||
-moz-box-shadow: #C8C8C8 0px 0px 3px;
|
||||
-webkit-box-shadow: #C8C8C8 0px 0px 3px;
|
||||
box-shadow: #C8C8C8 0px 0px 3px;
|
||||
border-color: #fff;
|
||||
outline: 0;
|
||||
text-shadow: none;
|
||||
@ -225,6 +255,7 @@ body.preview a.preview {
|
||||
border: 1px solid #ccc;
|
||||
-moz-box-shadow: #fff 0px 0px 5px;
|
||||
-webkit-box-shadow: #fff 0px 0px 5px;
|
||||
box-shadow: #fff 0px 0px 5px;
|
||||
|
||||
background-image:
|
||||
-webkit-gradient(
|
||||
@ -647,7 +678,6 @@ body.streaming {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
line-height: 20px;
|
||||
padding-left: 15px;
|
||||
text-shadow: #0A0 0px 1px 0px;
|
||||
display: block;
|
||||
background: #0c0;
|
||||
@ -655,6 +685,10 @@ body.streaming {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#streaming .msg {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#streaming a {
|
||||
text-shadow: #0A0 0px 1px 0px;
|
||||
color: #fff;
|
||||
@ -702,10 +736,10 @@ body {
|
||||
}
|
||||
|
||||
#streaming, #control, #bin {
|
||||
-webkit-transition: top 100ms ease-out;
|
||||
-o-transition: top 100ms ease-out;
|
||||
-moz-transition: top 100ms ease-out;
|
||||
transition: top 100ms ease-out;
|
||||
-webkit-transition: top 100ms ease-out, opacity 50ms linear;
|
||||
-o-transition: top 100ms ease-out, opacity 50ms linear;
|
||||
-moz-transition: top 100ms ease-out, opacity 50ms linear;
|
||||
transition: top 100ms ease-out, opacity 50ms linear;
|
||||
}
|
||||
|
||||
body.streaming #control,
|
||||
@ -783,9 +817,16 @@ ie6, li {
|
||||
|
||||
.button.download {
|
||||
padding-left: 24px;
|
||||
background-image: url(/images/arrow_down_12x12.png);
|
||||
/* background-image: url(/images/arrow_down_12x12.png);*/
|
||||
background-image: url(/images/download.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 8px 55%;
|
||||
background-position: 8px -33px;
|
||||
}
|
||||
|
||||
.button.download:hover {
|
||||
background-image: url(/images/download.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 8px 7px;
|
||||
}
|
||||
|
||||
/* attempt to get a live render preview in */
|
||||
@ -848,21 +889,281 @@ ie6, li {
|
||||
50,
|
||||
color-stop(0, #BFBFBF),
|
||||
color-stop(1, #949494)
|
||||
);
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
#live {
|
||||
background: white url(/images/jsbin-bg.gif) repeat-x 0 -62px;
|
||||
top: 0;
|
||||
left: 67%;
|
||||
border-top: 0;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.live #source {
|
||||
bottom: 0;
|
||||
right: 33%;
|
||||
}
|
||||
#live {
|
||||
background: white url(/images/jsbin-bg.gif) repeat-x 0 -62px;
|
||||
top: 0;
|
||||
left: 67%;
|
||||
border-top: 0;
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.live #source {
|
||||
bottom: 0;
|
||||
right: 33%;
|
||||
}
|
||||
|
||||
.autocomplete {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
border: 2px solid #DFE0B4;
|
||||
}
|
||||
|
||||
.autocomplete select {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none !important;
|
||||
background: #FFFFDB;
|
||||
border: 0;
|
||||
font-family: MenschRegular, Menlo, Monaco, consolas, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.showtip #bin {
|
||||
bottom: 26px;
|
||||
}
|
||||
|
||||
#tip {
|
||||
display: none;
|
||||
border-top: 1px solid #ccc;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
background: #fdfece;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 2px 10px 2px 20px;
|
||||
}
|
||||
|
||||
#tip p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#tip a.dismiss {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.showtip #tip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
details {
|
||||
position: absolute;
|
||||
display: block;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
font-size: 12px;
|
||||
background: #FEE0E0;
|
||||
color: #bb0000;
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
padding: 3px 5px;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
background: #FC9B9F;
|
||||
}
|
||||
|
||||
details ol {
|
||||
padding-left: 21px;
|
||||
max-height: 150px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
details li {
|
||||
margin: 5px 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* codemirror2 styles */
|
||||
@font-face {
|
||||
font-family: 'MenschRegular';
|
||||
src: url('/font/mensch-webfont.eot');
|
||||
src: url('/font/mensch-webfont.eot?#iefix') format('eot'),
|
||||
url('/font/mensch-webfont.woff') format('woff'),
|
||||
url('/font/mensch-webfont.ttf') format('truetype'),
|
||||
url('/font/mensch-webfont.svg#webfont0UwCC656') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
/*
|
||||
.editbox {
|
||||
margin: .4em;
|
||||
padding: 0;
|
||||
font-family: MenschRegular, Menlo, Monaco, consolas, monospace;
|
||||
font-size: 14pt;
|
||||
color: black;
|
||||
}*/
|
||||
|
||||
.CodeMirror > div {
|
||||
margin: .6em;
|
||||
}
|
||||
|
||||
.javascript .CodeMirror > div {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.html .CodeMirror > div {
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
.CodeMirror pre {
|
||||
/* white-space: pre-wrap !important;*/
|
||||
}
|
||||
|
||||
.editor .CodeMirror {
|
||||
height: 100%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
overflow: auto;
|
||||
height: 300px;
|
||||
/* top: 0;*/
|
||||
/* bottom: 0;*/
|
||||
/* line-height: 1em;*/
|
||||
font-size: 12px;
|
||||
font-family: MenschRegular, Menlo, Monaco, consolas, monospace;
|
||||
_position: relative; /* IE6 hack */
|
||||
}
|
||||
|
||||
.CodeMirror-gutter {
|
||||
position: absolute; left: 0; top: 0;
|
||||
background-color: #f7f7f7;
|
||||
border-right: 1px solid #eee;
|
||||
min-width: 2em;
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-gutter-text {
|
||||
color: #aaa;
|
||||
text-align: right;
|
||||
padding: .4em .2em .4em .4em;
|
||||
}
|
||||
.CodeMirror-lines {
|
||||
padding: .4em;
|
||||
}
|
||||
|
||||
.CodeMirror pre {
|
||||
-moz-border-radius: 0;
|
||||
-webkit-border-radius: 0;
|
||||
-o-border-radius: 0;
|
||||
border-radius: 0;
|
||||
border-width: 0; margin: 0; padding: 0; background: transparent;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
border-left: 1px solid black !important;
|
||||
}
|
||||
.CodeMirror-focused .CodeMirror-cursor {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
span.CodeMirror-selected {
|
||||
background: #ccc !important;
|
||||
color: HighlightText !important;
|
||||
}
|
||||
.CodeMirror-focused span.CodeMirror-selected {
|
||||
background: Highlight !important;
|
||||
}
|
||||
|
||||
.CodeMirror-matchingbracket {color: #0f0 !important;}
|
||||
.CodeMirror-nonmatchingbracket {color: #f22 !important;}
|
||||
|
||||
/* CM2 default */
|
||||
.cm-s-default span.cm-keyword {color: #708;}
|
||||
.cm-s-default span.cm-atom {color: #219;}
|
||||
.cm-s-default span.cm-number {color: #164;}
|
||||
.cm-s-default span.cm-def {color: #00f;}
|
||||
.cm-s-default span.cm-variable {color: black;}
|
||||
.cm-s-default span.cm-variable-2 {color: #05a;}
|
||||
.cm-s-default span.cm-variable-3 {color: #0a5;}
|
||||
.cm-s-default span.cm-property {color: black;}
|
||||
.cm-s-default span.cm-operator {color: black;}
|
||||
.cm-s-default span.cm-comment {color: #a50;}
|
||||
.cm-s-default span.cm-string {color: #a11;}
|
||||
.cm-s-default span.cm-meta {color: #555;}
|
||||
.cm-s-default span.cm-error {color: #f00;}
|
||||
.cm-s-default span.cm-qualifier {color: #555;}
|
||||
.cm-s-default span.cm-builtin {color: #30a;}
|
||||
.cm-s-default span.cm-bracket {color: #cc7;}
|
||||
.cm-s-default span.cm-tag {color: #170;}
|
||||
.cm-s-default span.cm-attribute {color: #00c;}
|
||||
|
||||
/* jsbin - based on web inspector */
|
||||
.cm-s-jsbin span.cm-keyword {color: #AA0D91;}
|
||||
.cm-s-jsbin span.cm-atom {color: #219;}
|
||||
.cm-s-jsbin span.cm-number {color: #164;}
|
||||
.cm-s-jsbin span.cm-def {color: #00f;}
|
||||
.cm-s-jsbin span.cm-variable {color: black;}
|
||||
.cm-s-jsbin span.cm-variable-2 {color: #05a;}
|
||||
.cm-s-jsbin span.cm-variable-3 {color: #0a5;}
|
||||
.cm-s-jsbin span.cm-property {color: black;}
|
||||
.cm-s-jsbin span.cm-operator {color: black;}
|
||||
.cm-s-jsbin span.cm-comment {color: #236E25;}
|
||||
.cm-s-jsbin span.cm-string {color: #C41A16;}
|
||||
.cm-s-jsbin span.cm-meta {color: #555;}
|
||||
.cm-s-jsbin span.cm-error {color: #f00;}
|
||||
.cm-s-jsbin span.cm-qualifier {color: #555;}
|
||||
.cm-s-jsbin span.cm-builtin {color: #30a;}
|
||||
.cm-s-jsbin span.cm-bracket {color: #cc7;}
|
||||
.cm-s-jsbin span.cm-tag {color: #881280;}
|
||||
.cm-s-jsbin span.cm-attribute {color: #994500;}
|
||||
|
||||
|
||||
/* neat */
|
||||
.cm-s-neat span.cm-comment { color: #a86; }
|
||||
.cm-s-neat span.cm-keyword { font-weight: bold; color: blue; }
|
||||
.cm-s-neat span.cm-string { color: #a22; }
|
||||
.cm-s-neat span.cm-builtin { font-weight: bold; color: #077; }
|
||||
.cm-s-neat span.cm-special { font-weight: bold; color: #0aa; }
|
||||
.cm-s-neat span.cm-variable { color: black; }
|
||||
.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; }
|
||||
.cm-s-neat span.cm-meta {color: #555;}
|
||||
|
||||
/* elegant */
|
||||
.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
|
||||
.cm-s-elegant span.cm-comment {color: #262;font-style: italic;}
|
||||
.cm-s-elegant span.cm-meta {color: #555;font-style: italic;}
|
||||
.cm-s-elegant span.cm-variable {color: black;}
|
||||
.cm-s-elegant span.cm-variable-2 {color: #b11;}
|
||||
.cm-s-elegant span.cm-qualifier {color: #555;}
|
||||
.cm-s-elegant span.cm-keyword {color: #730;}
|
||||
.cm-s-elegant span.cm-builtin {color: #30a;}
|
||||
.cm-s-elegant span.cm-error {background-color: #fdd;}
|
||||
|
||||
/* Loosely based on the Midnight Textmate theme */
|
||||
|
||||
.cm-s-night { background: #0a001f; color: #f8f8f8; }
|
||||
.cm-s-night span.CodeMirror-selected { background: #a8f !important; }
|
||||
.cm-s-night .CodeMirror-gutter { background: #0a001f; border-right: 1px solid #aaa; }
|
||||
.cm-s-night .CodeMirror-gutter-text { color: #f8f8f8; }
|
||||
.cm-s-night .CodeMirror-cursor { border-left: 1px solid white !important; }
|
||||
.cm-s-night span.cm-comment { color: #6900a1; }
|
||||
.cm-s-night span.cm-atom { color: #845dc4; }
|
||||
.cm-s-night span.cm-number { color: #ffd500; }
|
||||
.cm-s-night span.cm-keyword { color: #599eff; }
|
||||
.cm-s-night span.cm-string { color: #37f14a; }
|
||||
.cm-s-night span.cm-meta { color: #7678e2; }
|
||||
.cm-s-night span.cm-variable-2 { color: #99b2ff; }
|
||||
.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { white; }
|
||||
.cm-s-night span.cm-error { color: #9d1e15; }
|
||||
.cm-s-night span.cm-bracket { color: #8da6ce; }
|
||||
.cm-s-night span.cm-comment { color: #6900a1; }
|
||||
.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
|
||||
|
||||
#bin.ready {
|
||||
opacity: 1;
|
||||
}
|
||||
BIN
images/download.png
Normal file
BIN
images/download.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 229 B |
75
index.php
75
index.php
@ -22,38 +22,40 @@ if ($code_id) {
|
||||
<div class="control">
|
||||
<div class="buttons">
|
||||
<a class="tab button source group left" accesskey="1" href="#source">Code</a>
|
||||
<a class="tab button preview group right gap" accesskey="2" href="#preview">Preview</a>
|
||||
<a title="Revert" class="button light group left enable" id="revert" href="#"><img class="enabled" src="/images/revert.png" /><img class="disabled" src="/images/revert-disabled.png" /></a>
|
||||
<a class="tab button preview group right gap" accesskey="2" href="#preview" title="Run with alerts, prompts, etc">Render</a>
|
||||
<a title="Revert" class="button light group left" id="revert" href="#"><img class="enabled" src="/images/revert.png" /><img class="disabled" src="/images/revert-disabled.png" /></a>
|
||||
<?php if ($code_id) : ?>
|
||||
<a id="jsbinurl" class="button group light left" href="<?=HOST . $code_id?>"><?=HOST . $code_id?></a>
|
||||
<?php else : ?>
|
||||
<a id="save" class="button save group left right" href="/save">Save</a>
|
||||
<a id="save" class="button save group left" href="/save">Save</a>
|
||||
<?php endif ?>
|
||||
<?php if ($code_id) : ?><a id="save" class="button gap light save group right" href="<?=$code_id_path?>/save">Save changes</a><?php endif ?>
|
||||
<a id="stream" class="button left right" href="#stream">Stream</a>
|
||||
<?php if ($code_id) : ?><a id="save" class="button light save group" href="<?=$code_id_path?>/save">Save</a><?php endif ?>
|
||||
<a id="download" class="button download group right light gap" href="">Download</a>
|
||||
|
||||
<span id="panelsvisible" class="gap">View:
|
||||
<input type="checkbox" data-panel="javascript" id="showjavascript"><label for="showjavascript">JavaScript</label>
|
||||
<input type="checkbox" data-panel="html" id="showhtml"><label for="showhtml">HTML</label>
|
||||
<input type="checkbox" data-panel="live" id="showlive"><label for="showlive">Real-time preview</label>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="starting">
|
||||
|
||||
</div> -->
|
||||
<div class="help">
|
||||
<ul class="flat">
|
||||
<li><a id="startingpoint" href="#"><span>Save as my template</span></a></li>
|
||||
<!-- <li><a class="video" href="/about">About</a></li>
|
||||
<li><a class="video" href="#">Ajax Debugging</a></li> -->
|
||||
<li><a href="/help">Help & tutorials</a></li>
|
||||
<li><a target="_blank" href="http://jsbin.tumblr.com">Help & tutorials</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bin" class="stretch">
|
||||
<div id="bin" class="stretch" style="opacity: 0">
|
||||
<div id="source" class="binview stretch">
|
||||
<div class="code stretch javascript">
|
||||
<div class="label"><p><strong id="jslabel">JavaScript</strong><span> (<span class="hide">hide</span><span class="show">show</span> HTML)</span></p></div>
|
||||
<textarea id="javascript"></textarea>
|
||||
<div class="label"><p><strong id="jslabel">JavaScript</strong><!-- <span> (<span class="hide">hide</span><span class="show">show</span> HTML)</span> --></p></div>
|
||||
<div class="editbox">
|
||||
<textarea id="javascript"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="code stretch html">
|
||||
<div class="label">
|
||||
<p>HTML<span> (<span class="hide">hide</span><span class="show">show</span> JavaScript)</span></p>
|
||||
<p>HTML<!-- <span> (<span class="hide">hide</span><span class="show">show</span> JavaScript)</span> --></p>
|
||||
<label for="library">Include</label>
|
||||
<select id="library">
|
||||
<option value="none">None</option>
|
||||
@ -67,7 +69,9 @@ if ($code_id) {
|
||||
<option value="ext">Ext js</option>
|
||||
</select>
|
||||
</div>
|
||||
<textarea id="html"></textarea>
|
||||
<div class="editbox">
|
||||
<textarea id="html"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="live" class="stretch livepreview"><span class="close"></span></div>
|
||||
@ -76,8 +80,11 @@ if ($code_id) {
|
||||
<input type="hidden" name="method" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="help"><p><a href="/help/index.html">Help Menu</a></p><div id="content"></div></div>
|
||||
<?php
|
||||
<div id="tip"><p>You can jump to the latest bin by adding <code>/latest</code> to your URL</p><a class="dismiss" href="#">Dismiss x</a></div>
|
||||
<!-- <div id="help"><p><a href="/help/index.html">Help Menu</a></p><div id="content"></div></div> -->
|
||||
<script>
|
||||
<?php
|
||||
/*
|
||||
// construct the correct query string, if we're injecting the html or JS
|
||||
$qs = '';
|
||||
if (isset($_GET['js']) || isset($_GET['html']) || (@$_POST['inject'] && isset($_POST['html'])) ) {
|
||||
@ -95,18 +102,36 @@ if (@$_GET['js']) {
|
||||
if (@$_GET['html']) {
|
||||
$qs .= 'html=' . rawurlencode(stripslashes($_GET['html']));
|
||||
}
|
||||
*/
|
||||
|
||||
if (@$_POST['inject'] && @$_POST['html']) :
|
||||
$jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'));
|
||||
$html = '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $_POST['html']) . '"';
|
||||
?>
|
||||
<script>var template = { html : <?=$html?>, javascript: '' };</script>
|
||||
<?php else : ?>
|
||||
<script src="<?=$code_id_path ?>/source/<?=$qs?>"></script>
|
||||
<?php endif ?>
|
||||
<script src="http://forbind.net/js/?apikey=2796bc83070164231a3ab8c90227dbca"></script>
|
||||
var template = { html : <?=$html?>, javascript: '' };
|
||||
<?php else :
|
||||
/* <script src="<?=$code_id_path ?>/source/<?=$qs?>"></script> */
|
||||
list($code_id, $revision) = getCodeIdParams($request);
|
||||
|
||||
$edit_mode = false;
|
||||
|
||||
if ($code_id) {
|
||||
list($latest_revision, $html, $javascript) = getCode($code_id, $revision);
|
||||
} else {
|
||||
list($html, $javascript) = defaultCode();
|
||||
}
|
||||
|
||||
$url = HOST . $code_id . ($revision == 1 ? '' : '/' . $revision);
|
||||
if (!$ajax) {
|
||||
echo 'var template = ';
|
||||
}
|
||||
// doubles as JSON
|
||||
echo '{"url":"' . $url . '","html" : ' . encode($html) . ',"javascript":' . encode($javascript) . '}';
|
||||
|
||||
endif ?>
|
||||
</script>
|
||||
<script>jsbin = { version: "<?=VERSION?>" };</script>
|
||||
<script src="/js/<?=VERSION?>/jsbin.js"></script>
|
||||
<script>jsbin.version = "<?=VERSION?>";</script>
|
||||
<?php if (!OFFLINE) : ?>
|
||||
<script>
|
||||
var _gaq = _gaq || [];
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
//= require "storage"
|
||||
//= require "events"
|
||||
//= require "navigation"
|
||||
//= require "save"
|
||||
//= require "file-drop"
|
||||
//= require "errors"
|
||||
//= require "download"
|
||||
//= require "../render/live"
|
||||
//= require "tips"
|
||||
this.livePreview = function () {
|
||||
$('#live').trigger('toggle');
|
||||
};
|
||||
|
||||
var debug = false,
|
||||
var debug = jsbin.settings.debug === undefined ? false : jsbin.settings.debug,
|
||||
documentTitle = null, // null = JS Bin
|
||||
$bin = $('#bin'),
|
||||
loadGist,
|
||||
$document = $(document),
|
||||
@ -13,17 +16,24 @@ var debug = false,
|
||||
sessionStorage.setItem('html', editors.html.getCode());
|
||||
sessionStorage.setItem('url', template.url);
|
||||
|
||||
localStorage.setItem('settings', JSON.stringify(jsbin.settings));
|
||||
|
||||
var panel = getFocusedPanel();
|
||||
sessionStorage.setItem('panel', panel);
|
||||
try { // this causes errors in IE9 - so we'll use a try/catch to get through it
|
||||
sessionStorage.setItem('line', editors[panel].currentLine());
|
||||
sessionStorage.setItem('character', editors[panel].cursorPosition().character);
|
||||
sessionStorage.setItem('line', editors[panel].getCursor().line);
|
||||
sessionStorage.setItem('character', editors[panel].getCursor().ch);
|
||||
} catch (e) {
|
||||
sessionStorage.setItem('line', 0);
|
||||
sessionStorage.setItem('character', 0);
|
||||
}
|
||||
};
|
||||
|
||||
//= require "storage"
|
||||
//= require "events"
|
||||
//= require "navigation"
|
||||
//= require "save"
|
||||
//= require "file-drop"
|
||||
|
||||
$(window).unload(unload);
|
||||
|
||||
@ -49,9 +59,26 @@ if (window.location.hash == '#preview') {
|
||||
}
|
||||
|
||||
$document.one('jsbinReady', function () {
|
||||
if (localStorage && localStorage.getItem('livepreview') == 'true') { // damn string coersion
|
||||
$('#live').trigger('show');
|
||||
// if (localStorage && localStorage.getItem('livepreview') == 'true') { // damn string coersion
|
||||
// $('#live').trigger('show');
|
||||
// }
|
||||
|
||||
$('.code.html').splitter();
|
||||
$live.splitter();
|
||||
|
||||
for (panel in jsbin.settings.show) {
|
||||
if (jsbin.settings.show[panel]) {
|
||||
$('#show' + panel).attr('checked', 'checked')[0].checked = true;
|
||||
} else {
|
||||
$('#show' + panel).removeAttr('checked')[0].checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (panel in jsbin.settings.show) {
|
||||
updatePanel(panel, jsbin.settings.show[panel]);
|
||||
}
|
||||
|
||||
$bin.removeAttr('style').addClass('ready');
|
||||
});
|
||||
|
||||
// if a gist has been requested, lazy load the gist library and plug it in
|
||||
@ -70,39 +97,10 @@ if (/gist\/\d+/.test(window.location.pathname) && (!sessionStorage.getItem('java
|
||||
}
|
||||
}
|
||||
|
||||
$('div.label p').click(function () {
|
||||
// determine which side was clicked
|
||||
var panel = $(this).closest('.code').is('.javascript') ? 'javascript' : 'html',
|
||||
otherpanel = panel == 'javascript' ? 'html' : 'javascript',
|
||||
mustshow = $bin.is('.' + panel + '-only'),
|
||||
speed = 150,
|
||||
animatePanel = animateOtherPanel = {};
|
||||
|
||||
if ($bin.is('.' + panel + '-only')) { // showing the panel
|
||||
// only the html tab could have been clicked
|
||||
animatePanel = panel == 'html' ? { left: '50%', width: '50%' } : { left: '0%', width: '50%' };
|
||||
animateOtherPanel = otherpanel == 'javascript' ? { left: '0%' } : { left: '50%' };
|
||||
$bin.find('div.' + panel).animate(animatePanel, speed);
|
||||
$bin.find('div.' + otherpanel).show().animate(animateOtherPanel, speed, function () {
|
||||
$bin.removeClass(panel + '-only');
|
||||
localStorage && localStorage.removeItem('visible-panel');
|
||||
});
|
||||
} else { // hiding other panel
|
||||
animatePanel = panel == 'html' ? { left: '0%', width: '100%' } : { width: '100%' };
|
||||
animateOtherPanel = otherpanel == 'javascript' ? { left: '-50%' } : { left: '100%' };
|
||||
|
||||
$bin.find('div.' + panel).animate(animatePanel, speed);
|
||||
$bin.find('div.' + otherpanel).animate(animateOtherPanel, speed, function () {
|
||||
$(this).hide();
|
||||
$bin.addClass(panel + '-only');
|
||||
// makes me sad, but we have to put this in a try/catch because Safari
|
||||
// sometimes throws an error when using localStorage, then jQuery goes
|
||||
// in to an infinite loop if an animation callback throws an exeception!
|
||||
try {
|
||||
// we're not reading 'true', only that it's been set
|
||||
localStorage && localStorage.setItem('visible-panel', panel);
|
||||
} catch (e) {}
|
||||
});
|
||||
$document.keydown(function (event) {
|
||||
if (event.metaKey && event.which == 83) {
|
||||
$('#save').click();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,17 +1,10 @@
|
||||
window.jsbin = {};
|
||||
|
||||
// once these features are live, they come out of the jsbin beta box
|
||||
(function () {
|
||||
var $body = $('body');
|
||||
|
||||
//= require "download"
|
||||
|
||||
this.on = function () {
|
||||
localStorage.setItem('beta', 'true');
|
||||
$body.addClass('beta');
|
||||
|
||||
enableDownload();
|
||||
enableLive();
|
||||
};
|
||||
|
||||
this.off = function () {
|
||||
@ -22,95 +15,5 @@ window.jsbin = {};
|
||||
this.active = localStorage.getItem('beta') == 'true' || false;
|
||||
if (this.active) this.on();
|
||||
|
||||
//= require "stream"
|
||||
// expose...for now
|
||||
window.stream = this.stream;
|
||||
|
||||
//= require "../render/live"
|
||||
this.livePreview = function () {
|
||||
$('#live').trigger('toggle');
|
||||
};
|
||||
|
||||
//= require "../vendor/jshint/jshint"
|
||||
//= require "../vendor/jquery.tipsy"
|
||||
this.jshint = function () {
|
||||
var source = editors.javascript.getCode();
|
||||
var ok = JSHINT(source);
|
||||
|
||||
return ok ? true : JSHINT.data();
|
||||
};
|
||||
|
||||
var $error = $('<em>errors</em>').hide();
|
||||
$('#jslabel').append($error);
|
||||
|
||||
// modify JSHINT to only return errors that are of value (to me, for displaying)
|
||||
JSHINT._data = JSHINT.data;
|
||||
JSHINT.data = function (onlyErrors) {
|
||||
var data = JSHINT._data(),
|
||||
errors = [];
|
||||
|
||||
if (onlyErrors && data.errors) {
|
||||
for (var i = 0; i < data.errors.length; i++) {
|
||||
if (data.errors[i] !== null && data.errors[i].evidence) { // ignore JSHINT just quitting
|
||||
errors.push(data.errors[i]);
|
||||
}
|
||||
}
|
||||
return {
|
||||
errors: errors
|
||||
};
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
$error.tipsy({
|
||||
title: function () {
|
||||
var html = ['<ul>'],
|
||||
errors = JSHINT.data(true).errors;
|
||||
for (var i = 0; i < errors.length; i++) {
|
||||
html.push('Line ' + errors[i].line + ': ' + errors[i].evidence + ' --- ' + errors[i].reason);
|
||||
}
|
||||
|
||||
return html.join('<li>') + '</ul>';
|
||||
},
|
||||
gravity: 'nw',
|
||||
html: true
|
||||
});
|
||||
|
||||
$error.click(function () {
|
||||
var errors = JSHINT.data(true).errors;
|
||||
if (errors.length) {
|
||||
var line = editors.javascript.nthLine(errors[0].line);
|
||||
editors.javascript.jumpToLine(line);
|
||||
editors.javascript.selectLines(line, 0, editors.javascript.nthLine(errors[0].line + 1), 0);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
var checkForErrors = function () {
|
||||
var jshint = jsbin.jshint(),
|
||||
errors = '';
|
||||
|
||||
if (jshint === true) {
|
||||
$error.text('').hide();
|
||||
} else {
|
||||
errors = JSHINT.data(true).errors.length;
|
||||
errors = errors == 1 ? '1 error' : errors + ' errors';
|
||||
$error.text('(' + errors + ')').show();
|
||||
}
|
||||
};
|
||||
|
||||
$(document).bind('codeChange', throttle(checkForErrors, 1000));
|
||||
$(document).bind('jsbinReady', checkForErrors);
|
||||
}).call(jsbin);
|
||||
|
||||
function throttle(fn, delay) {
|
||||
var timer = null;
|
||||
return function () {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(context, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
//= require "stream"
|
||||
}).call(jsbin);
|
||||
@ -1,6 +1,5 @@
|
||||
function enableDownload() {
|
||||
$('#save').removeClass('right gap').after('<a id="download" class="button download group right light gap" href="">Download</a>');
|
||||
|
||||
(function () {
|
||||
|
||||
var $revert = $('#revert');
|
||||
$('#download').click(function (event) {
|
||||
event.preventDefault();
|
||||
@ -15,4 +14,6 @@ function enableDownload() {
|
||||
}); // triggers via ajax
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
107
js/chrome/errors.js
Normal file
107
js/chrome/errors.js
Normal file
@ -0,0 +1,107 @@
|
||||
//= require "../vendor/jshint/jshint"
|
||||
//= require "../vendor/jquery.tipsy"
|
||||
var jshint = function () {
|
||||
var source = editors.javascript.getCode();
|
||||
var ok = JSHINT(source);
|
||||
|
||||
return ok ? true : JSHINT.data();
|
||||
};
|
||||
|
||||
var detailsSupport = 'open' in document.createElement('details');
|
||||
|
||||
var $error = $('<details><summary>errors</summary></details>').hide();
|
||||
$('#source .javascript').append($error);
|
||||
|
||||
$error.find('summary').click(function () {
|
||||
if (!detailsSupport) {
|
||||
$(this).nextAll().toggle();
|
||||
$error[0].open = !$error[0].open;
|
||||
}
|
||||
// trigger a resize after the click has completed and the details is close
|
||||
setTimeout(function () {
|
||||
$document.trigger('sizeeditors');
|
||||
}, 10);
|
||||
});
|
||||
|
||||
if (!detailsSupport) {
|
||||
$error[0].open = false;
|
||||
}
|
||||
|
||||
// modify JSHINT to only return errors that are of value (to me, for displaying)
|
||||
JSHINT._data = JSHINT.data;
|
||||
JSHINT.data = function (onlyErrors) {
|
||||
var data = JSHINT._data(),
|
||||
errors = [];
|
||||
|
||||
if (onlyErrors && data.errors) {
|
||||
for (var i = 0; i < data.errors.length; i++) {
|
||||
if (data.errors[i] !== null && data.errors[i].evidence) { // ignore JSHINT just quitting
|
||||
errors.push(data.errors[i]);
|
||||
}
|
||||
}
|
||||
return {
|
||||
errors: errors
|
||||
};
|
||||
} else {
|
||||
data.errors = [];
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
// $error.tipsy({
|
||||
// title: function () {
|
||||
// var html = ['<ul>'],
|
||||
// errors = JSHINT.data(true).errors;
|
||||
// for (var i = 0; i < errors.length; i++) {
|
||||
// html.push('Line ' + errors[i].line + ': ' + errors[i].evidence + ' --- ' + errors[i].reason);
|
||||
// }
|
||||
//
|
||||
// return html.join('<li>') + '</ul>';
|
||||
// },
|
||||
// gravity: 'nw',
|
||||
// html: true
|
||||
// });
|
||||
|
||||
$error.delegate('li', 'click', function () {
|
||||
var errors = JSHINT.data(true).errors;
|
||||
if (errors.length) {
|
||||
var i = $error.find('li').index(this);
|
||||
editors.javascript.setSelection({ line: errors[i].line - 1, ch: 0 }, { line: errors[i].line - 1 });
|
||||
editors.javascript.focus();
|
||||
// var line = editors.javascript.nthLine(errors[0].line);
|
||||
// editors.javascript.jumpToLine(line);
|
||||
// editors.javascript.selectLines(line, 0, editors.javascript.nthLine(errors[0].line + 1), 0);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
var checkForErrors = function () {
|
||||
var hint = jshint(),
|
||||
jshintErrors = JSHINT.data(true),
|
||||
errors = '',
|
||||
visible = $error.is(':visible');
|
||||
|
||||
if (hint === true && visible) {
|
||||
$error.hide();
|
||||
$document.trigger('sizeeditors');
|
||||
} else if (jshintErrors.errors.length) {
|
||||
var html = ['<ol>'],
|
||||
errors = jshintErrors.errors;
|
||||
for (var i = 0; i < errors.length; i++) {
|
||||
html.push('Line ' + errors[i].line + ': ' + errors[i].evidence + ' --- ' + errors[i].reason);
|
||||
}
|
||||
|
||||
html = html.join('<li>') + '</ol>';
|
||||
|
||||
$error.find('summary').text(jshintErrors.errors.length == 1 ? '1 error' : jshintErrors.errors.length + ' errors');
|
||||
$error.find('ol').remove();
|
||||
|
||||
if (!detailsSupport && $error[0].open == false) html = $(html).hide();
|
||||
|
||||
$error.append(html).show();
|
||||
$document.trigger('sizeeditors');
|
||||
}
|
||||
};
|
||||
|
||||
$(document).bind('codeChange', throttle(checkForErrors, 1000));
|
||||
$(document).bind('jsbinReady', checkForErrors);
|
||||
@ -1,22 +1,76 @@
|
||||
$('#startingpoint').click(function () {
|
||||
if (localStorage) {
|
||||
localStorage.setItem('saved-javascript', editors.javascript.getCode());
|
||||
localStorage.setItem('saved-html', editors.html.getCode());
|
||||
// $('#startingpoint').click(function () {
|
||||
// if (localStorage) {
|
||||
// localStorage.setItem('saved-javascript', editors.javascript.getCode());
|
||||
// localStorage.setItem('saved-html', editors.html.getCode());
|
||||
//
|
||||
// // fade text out - then show "saved", then bring it back in again
|
||||
// $(this).find('span:first').fadeOut(200, function () {
|
||||
// $(this).next().fadeIn(200).animate({ foo: 1 }, 1000, function () {
|
||||
// $(this).fadeOut(200, function () {
|
||||
// $(this).prev().fadeIn(150);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// return false;
|
||||
// }).find('span').after('<span style="display: none;">Saved</span>');
|
||||
|
||||
var $htmlpanel = $('.code.html'),
|
||||
htmlsplitter = null;
|
||||
|
||||
// fade text out - then show "saved", then bring it back in again
|
||||
$(this).find('span:first').fadeOut(200, function () {
|
||||
$(this).next().fadeIn(200).animate({ foo: 1 }, 1000, function () {
|
||||
$(this).fadeOut(200, function () {
|
||||
$(this).prev().fadeIn(150);
|
||||
});
|
||||
});
|
||||
});
|
||||
function updatePanel(panel, show) {
|
||||
jsbin.settings.show[panel] = show;
|
||||
htmlsplitter = htmlsplitter || $htmlpanel.data().splitter;
|
||||
|
||||
if (panel == 'live') {
|
||||
$('#live').trigger(show ? 'show' : 'hide');
|
||||
htmlsplitter.trigger('init'); // update the position of the html splitter
|
||||
} else {
|
||||
var $panel = $bin.find('.code.' + panel)[show ? 'show' : 'hide']();
|
||||
|
||||
if (!show) {
|
||||
htmlsplitter.hide();
|
||||
} else {
|
||||
htmlsplitter.show();
|
||||
}
|
||||
|
||||
var $otherpanel = panel == 'html' ? $bin.find('.code.javascript') : $bin.find('.code.html'),
|
||||
visible = $panelsvisible.filter(':not([data-panel="live"]):checked').length,
|
||||
$othercheckbox = $panelsvisible.filter('[data-panel=' + (panel == 'html' ? 'javascript' : 'html') + ']');
|
||||
|
||||
// logic was only revealed by going through every possible combination. Hey, it was late :(
|
||||
if (visible === 1 && show == false) {
|
||||
// stretch
|
||||
$othercheckbox.attr('disabled', 'disabled');
|
||||
if (panel == 'html') { // only JavaScript remains
|
||||
$otherpanel.data('style', { 'right': $otherpanel.css('right') });
|
||||
$otherpanel.css('right', '0');
|
||||
} else if (panel == 'javascript') { // only HTML remains
|
||||
$otherpanel.data('style', {'left' : $otherpanel.css('left') });
|
||||
$otherpanel.css('left', '0');
|
||||
}
|
||||
} else {
|
||||
$othercheckbox.removeAttr('disabled');
|
||||
// restore CSS positions
|
||||
$otherpanel.attr('style', $otherpanel.data('style'));
|
||||
}
|
||||
|
||||
if (show) {
|
||||
editors[panel].refresh();
|
||||
}
|
||||
|
||||
htmlsplitter.trigger('init'); // on show or hide - recalc the splitter position
|
||||
}
|
||||
return false;
|
||||
}).find('span').after('<span style="display: none;">Saved</span>');
|
||||
}
|
||||
|
||||
var $panelsvisible = $('#panelsvisible input').click(function () {
|
||||
var checked = this.checked,
|
||||
panel = $(this).data('panel');
|
||||
|
||||
updatePanel(panel, checked);
|
||||
});
|
||||
|
||||
var $revert = $('#revert').click(function () {
|
||||
|
||||
if ($revert.is(':not(.enable)')) {
|
||||
return false;
|
||||
}
|
||||
@ -39,51 +93,49 @@ var $revert = $('#revert').click(function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
var $stream = $('#stream').click(function () {
|
||||
stream.create();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#control .tab').click(function (event) {
|
||||
event.preventDefault();
|
||||
// event.preventDefault();
|
||||
$('body').removeClass('source preview').addClass(this.hash.substr(1));
|
||||
|
||||
if ($(this).is('.preview')) {
|
||||
$('#preview iframe').remove();
|
||||
$('#preview').append('<iframe class="stretch"></iframe>');
|
||||
renderPreview();
|
||||
} else {
|
||||
// remove iframe and thus removing any (I *think*) memory resident JS
|
||||
$('#preview iframe').remove();
|
||||
editors[getFocusedPanel()].focus();
|
||||
}
|
||||
});
|
||||
|
||||
$('#control div.help a:last').click(function () {
|
||||
$(window).trigger('togglehelp');
|
||||
return false;
|
||||
});
|
||||
// $('#control div.help a:last').click(function () {
|
||||
// $(window).trigger('togglehelp');
|
||||
// return false;
|
||||
// });
|
||||
|
||||
$('#help a:host(' + window.location.host + ')').live('click', function () {
|
||||
$('#help #content').load(this.href + '?' + Math.random());
|
||||
return false;
|
||||
});
|
||||
// $('#help a:host(' + window.location.host + ')').live('click', function () {
|
||||
// $('#help #content').load(this.href + '?' + Math.random());
|
||||
// return false;
|
||||
// });
|
||||
|
||||
var helpOpen = false;
|
||||
$(window).bind('togglehelp', function () {
|
||||
var s = 100, right = helpOpen ? 0 : 300;
|
||||
|
||||
if (helpOpen == false) {
|
||||
$('#help #content').load('/help/index.html?' + Math.random());
|
||||
}
|
||||
$bin.find('> div').animate({ right: right }, { duration: s });
|
||||
$('#control').animate({ right: right }, { duration: s });
|
||||
|
||||
$('#help').animate({ right: helpOpen ? -300 : 0 }, { duration: s});
|
||||
|
||||
helpOpen = helpOpen ? false : true;
|
||||
});
|
||||
|
||||
$(document).keyup(function (event) {
|
||||
if (helpOpen && event.keyCode == 27) {
|
||||
$(window).trigger('togglehelp');
|
||||
}
|
||||
});
|
||||
// var helpOpen = false;
|
||||
// $(window).bind('togglehelp', function () {
|
||||
// var s = 100, right = helpOpen ? 0 : 300;
|
||||
//
|
||||
// if (helpOpen == false) {
|
||||
// $('#help #content').load('/help/index.html?' + Math.random());
|
||||
// }
|
||||
// $bin.find('> div').animate({ right: right }, { duration: s });
|
||||
// $('#control').animate({ right: right }, { duration: s });
|
||||
//
|
||||
// $('#help').animate({ right: helpOpen ? -300 : 0 }, { duration: s});
|
||||
//
|
||||
// helpOpen = helpOpen ? false : true;
|
||||
// });
|
||||
//
|
||||
// $(document).keyup(function (event) {
|
||||
// if (helpOpen && event.keyCode == 27) {
|
||||
// $(window).trigger('togglehelp');
|
||||
// }
|
||||
// });
|
||||
|
||||
@ -28,7 +28,7 @@ function saveCode(method, ajax, ajaxCallback) {
|
||||
if (window.history && window.history.pushState) {
|
||||
window.history.pushState(null, data.edit, data.edit);
|
||||
|
||||
$('#jsbinurl').attr('href', data.edit).text(data.url);
|
||||
$('#jsbinurl').attr('href', data.url).text(data.url);
|
||||
} else {
|
||||
window.location = data.edit;
|
||||
}
|
||||
|
||||
86
js/chrome/splitter.js
Normal file
86
js/chrome/splitter.js
Normal file
@ -0,0 +1,86 @@
|
||||
$.fn.splitter = function () {
|
||||
var $document = $(document);
|
||||
var splitterSettings = JSON.parse(localStorage.getItem('splitterSettings') || '[]');
|
||||
return this.each(function () {
|
||||
var $el = $(this),
|
||||
guid = $.fn.splitter.guid++,
|
||||
$parent = $el.parent(),
|
||||
$prev = $el.prev(),
|
||||
$handle = $('<div class="resize"></div>'),
|
||||
$blocker = $('<div class="block" />').css({ cursor: 'pointer', position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, 'z-index': 99999, width: '100%', height: '100%' }),
|
||||
dragging = false,
|
||||
width = $parent.width(),
|
||||
left = $parent.offset().left,
|
||||
settings = splitterSettings[guid] || {};
|
||||
|
||||
function moveSplitter(posX) {
|
||||
var x = posX - left,
|
||||
split = 100 / width * x;
|
||||
|
||||
if (split > 10 && split < 90) {
|
||||
$el.css('left', split + '%');
|
||||
$prev.css('right', (100 - split) + '%');
|
||||
$handle.css({
|
||||
left: split + '%'
|
||||
});
|
||||
settings.x = posX;
|
||||
splitterSettings[guid] = settings;
|
||||
console.log('set: ', JSON.stringify(splitterSettings));
|
||||
localStorage.setItem('splitterSettings', JSON.stringify(splitterSettings));
|
||||
}
|
||||
}
|
||||
|
||||
$document.mouseup(function () {
|
||||
dragging = false;
|
||||
$blocker.remove();
|
||||
$handle.css('opacity', '0');
|
||||
}).mousemove(function (event) {
|
||||
if (dragging) {
|
||||
moveSplitter(event.pageX);
|
||||
}
|
||||
});
|
||||
|
||||
$handle.mousedown(function (e) {
|
||||
dragging = true;
|
||||
$('body').append($blocker);
|
||||
// TODO layer on div to block iframes from stealing focus
|
||||
width = $parent.width();
|
||||
left = $parent.offset().left;
|
||||
e.preventDefault();
|
||||
}).hover(function () {
|
||||
$handle.css('opacity', '1');
|
||||
}, function () {
|
||||
if (!dragging) {
|
||||
$handle.css('opacity', '0');
|
||||
}
|
||||
});
|
||||
|
||||
$handle.bind('init', function (event, x) {
|
||||
$handle.css({
|
||||
top: 0,
|
||||
// left: (100 / width * $el.offset().left) + '%',
|
||||
bottom: 0,
|
||||
width: 4,
|
||||
opacity: 0,
|
||||
position: 'absolute',
|
||||
cursor: 'pointer',
|
||||
'border-left': '1px solid rgba(218, 218, 218, 0.5)',
|
||||
'z-index': 99999
|
||||
});
|
||||
|
||||
if ($el.is(':hidden')) {
|
||||
$handle.hide();
|
||||
} else {
|
||||
moveSplitter(x || $el.offset().left);
|
||||
}
|
||||
}).trigger('init', settings.x || $el.offset().left);
|
||||
|
||||
$prev.css('width', 'auto');
|
||||
$el.data('splitter', $handle);
|
||||
$el.before($handle);
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.splitter.guid = 0;
|
||||
@ -17,7 +17,7 @@ var requiresCookies = (function () {
|
||||
|
||||
// Firefox with Cookies disabled triggers a security error when we probe window.sessionStorage
|
||||
// currently we're just disabling all the session features if that's the case.
|
||||
var sessionStorage, localStorage;
|
||||
var sessionStorage = window.sessionStorage, localStorage = window.localStorage;
|
||||
|
||||
if (!requiresCookies && window.sessionStorage) {
|
||||
sessionStorage = window.sessionStorage;
|
||||
|
||||
@ -1,191 +1,245 @@
|
||||
(function (global) {
|
||||
var $stream = $('<div id="streaming"><span class="msg"></span><span class="n"></span><span class="listen"> (click here to <span class="resume">resume</span><span class="pause">pause</span>)</span></div>').prependTo('body'),
|
||||
streaming = false,
|
||||
$body = $('body'),
|
||||
key = null,
|
||||
captureTimer = null,
|
||||
last = {},
|
||||
owner = false;
|
||||
//= require "../vendor/diff_match_patch_uncompressed"
|
||||
|
||||
function capture() {
|
||||
var javascript = editors.javascript.getCode(),
|
||||
html = editors.html.getCode(),
|
||||
changed = false,
|
||||
msg = {};
|
||||
|
||||
if (javascript != last.javascript) {
|
||||
msg.javascript = javascript;
|
||||
changed = true;
|
||||
var context = this;
|
||||
|
||||
var script = document.createElement('script');
|
||||
script.src = 'http://forbind.net/js/';
|
||||
document.body.appendChild(script);
|
||||
|
||||
setTimeout(function forbindReady() {
|
||||
if (typeof window.forbind !== 'undefined') {
|
||||
forbind.apikey = '2796bc83070164231a3ab8c90227dbca';
|
||||
console.log('forbind ready');
|
||||
initForbind(context);
|
||||
} else {
|
||||
setTimeout(forbindReady, 20);
|
||||
}
|
||||
|
||||
if (html != last.html) {
|
||||
msg.html = html;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
last = {
|
||||
javascript: javascript,
|
||||
html: html
|
||||
};
|
||||
|
||||
msg.panel = getFocusedPanel();
|
||||
|
||||
msg.line = editors[msg.panel].currentLine();
|
||||
msg.character = editors[msg.panel].cursorPosition().character;
|
||||
|
||||
forbind.send(msg);
|
||||
}
|
||||
}
|
||||
}, 20);
|
||||
|
||||
forbind.on({
|
||||
join: function (event) {
|
||||
$body.addClass('streaming').removeClass('pausestream');
|
||||
streaming = true;
|
||||
|
||||
if (event.isme) {
|
||||
$('#stream').fadeOut('fast').prev().addClass('right');
|
||||
}
|
||||
|
||||
if (event.isme && event.readonlykey) {
|
||||
owner = true;
|
||||
sessionStorage.setItem('streamwritekey', event.readonlykey);
|
||||
sessionStorage.setItem('streamkey', key);
|
||||
function initForbind(global) {
|
||||
var $stream = $('<div id="streaming"><span class="msg"></span><span class="n"></span><span class="listen"> (click here to <span class="resume">resume</span><span class="pause">pause</span>)</span></div>').prependTo('body'),
|
||||
streaming = false,
|
||||
$body = $('body'),
|
||||
key = null,
|
||||
captureTimer = null,
|
||||
last = {},
|
||||
owner = false;
|
||||
|
||||
function changes(lang, code) {
|
||||
var msg = {},
|
||||
diff,
|
||||
patch,
|
||||
result;
|
||||
|
||||
var type, editorTimer = { javascript: null, html: null };
|
||||
|
||||
// this code is completely over the top - need to simplify
|
||||
$stream.find('.msg').html('streaming on <a href="/?stream=' + key + '">http://jsbin.com/?stream=' + key + '</a> to #');
|
||||
|
||||
$stream.removeClass('listen');
|
||||
|
||||
for (type in editors) {
|
||||
(function (type) {
|
||||
try {
|
||||
$(editors[type].win.document).bind('keyup', function () {
|
||||
if (streaming) {
|
||||
clearTimeout(editorTimer[type]);
|
||||
editorTimer[type] = setTimeout(capture, 250);
|
||||
}
|
||||
});
|
||||
} catch (e) {}
|
||||
})(type);
|
||||
}
|
||||
|
||||
$(document).bind('codeChange', capture);
|
||||
|
||||
}
|
||||
|
||||
updateCount(event);
|
||||
},
|
||||
leave: function (event) {
|
||||
if (event.isme) {
|
||||
if (!owner) {
|
||||
$body.addClass('pausestream');
|
||||
streaming = false;
|
||||
|
||||
$stream.one('click', function () {
|
||||
window.location.search.replace(/stream=(.+?)\b/, function (n, key) {
|
||||
global.stream.join(key);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$body.removeClass('streaming');
|
||||
owner = false;
|
||||
sessionStorage.removeItem('streamkey');
|
||||
sessionStorage.removeItem('streamwritekey');
|
||||
}
|
||||
}
|
||||
|
||||
updateCount(event);
|
||||
},
|
||||
message: function (msg) {
|
||||
var code = msg.data;
|
||||
if (code.javascript) {
|
||||
editors.javascript.setCode(code.javascript);
|
||||
}
|
||||
|
||||
if (code.html) {
|
||||
editors.html.setCode(code.html);
|
||||
$(document).trigger('codeChange');
|
||||
}
|
||||
|
||||
// update preview if required
|
||||
if ($body.is('.preview')) {
|
||||
$('#preview').append('<iframe class="stretch"></iframe>');
|
||||
renderPreview();
|
||||
if (last[lang] === undefined) {
|
||||
msg.text = code;
|
||||
msg.diff = false;
|
||||
} else {
|
||||
var focused = editors[code.panel];
|
||||
focused.focus();
|
||||
focused.selectLines(focused.nthLine(code.line), code.character);
|
||||
diff = new diff_match_patch();
|
||||
// 1. get diffs
|
||||
patch = diff.patch_make(last[lang], code);
|
||||
// 2. apply patch to old javascript
|
||||
result = diff.patch_apply(patch, last[lang]);
|
||||
|
||||
// 3. if it matches, then send diff
|
||||
if (result[0] == code) {
|
||||
msg.text = diff.patch_toText(patch);
|
||||
msg.diff = true;
|
||||
// 4. otherwise, send entire code
|
||||
} else {
|
||||
msg.text = code;
|
||||
msg.diff = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (data) {
|
||||
console.log('error in forbind', data);
|
||||
|
||||
last[lang] = code;
|
||||
|
||||
return msg;
|
||||
}
|
||||
});
|
||||
|
||||
function updateCount(data) {
|
||||
if (owner) {
|
||||
var txt = (data.total - 1) == 1 ? ' user' : ' users';
|
||||
$stream.find('.n').html((data.total - 1) + txt);
|
||||
function capture() {
|
||||
var javascript = editors.javascript.getCode(),
|
||||
html = editors.html.getCode(),
|
||||
changed = false,
|
||||
cursor,
|
||||
msg = {};
|
||||
|
||||
msg.javascript = changes('javascript', javascript);
|
||||
msg.html = changes('html', html);
|
||||
|
||||
if (msg.html.text || msg.javascript.text) {
|
||||
msg.panel = getFocusedPanel();
|
||||
|
||||
cursor = editors[msg.panel].getCursor();
|
||||
|
||||
msg.line = cursor.line;
|
||||
msg.ch = cursor.ch;
|
||||
|
||||
console.log('sending', msg);
|
||||
|
||||
forbind.send(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global.stream = {
|
||||
create: function () {
|
||||
key = (Math.abs(~~(Math.random()*+new Date))).toString(32); // OTT?
|
||||
if (typeof window.forbind !== 'undefined') forbind.on({
|
||||
join: function (event) {
|
||||
$body.addClass('streaming').removeClass('pausestream');
|
||||
streaming = true;
|
||||
|
||||
if (event.isme) {
|
||||
$('#stream').fadeOut('fast').prev().addClass('right');
|
||||
}
|
||||
|
||||
if (event.isme && event.readonlykey) {
|
||||
owner = true;
|
||||
sessionStorage.setItem('streamwritekey', event.readonlykey);
|
||||
sessionStorage.setItem('streamkey', key);
|
||||
|
||||
var type, editorTimer = { javascript: null, html: null };
|
||||
|
||||
// this code is completely over the top - need to simplify
|
||||
$stream.find('.msg').html('streaming on <a href="/?stream=' + key + '">http://jsbin.com/?stream=' + key + '</a> to #');
|
||||
|
||||
$stream.removeClass('listen');
|
||||
|
||||
// for (type in editors) {
|
||||
// (function (type) {
|
||||
// try {
|
||||
// $(editors[type].win.document).bind('keyup', throttle(function () {
|
||||
// if (streaming) {
|
||||
// console.log('capture?');
|
||||
// capture();
|
||||
// }
|
||||
// }, 250));
|
||||
// } catch (e) {}
|
||||
// })(type);
|
||||
// }
|
||||
|
||||
$(document).bind('codeChange', throttle(capture, 250));
|
||||
|
||||
}
|
||||
|
||||
updateCount(event);
|
||||
},
|
||||
leave: function (event) {
|
||||
if (event.isme) {
|
||||
if (!owner) {
|
||||
$body.addClass('pausestream');
|
||||
streaming = false;
|
||||
|
||||
$stream.one('click', function () {
|
||||
window.location.search.replace(/stream=(.+?)\b/, function (n, key) {
|
||||
global.stream.join(key);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$body.removeClass('streaming');
|
||||
owner = false;
|
||||
sessionStorage.removeItem('streamkey');
|
||||
sessionStorage.removeItem('streamwritekey');
|
||||
}
|
||||
}
|
||||
|
||||
updateCount(event);
|
||||
},
|
||||
message: function (event) {
|
||||
var msg = event.data;
|
||||
updateCode(msg.javascript, 'javascript');
|
||||
updateCode(msg.html, 'html');
|
||||
|
||||
// update preview if required
|
||||
if ($body.is('.preview')) {
|
||||
$('#preview').remove('iframe').append('<iframe class="stretch"></iframe>');
|
||||
renderPreview();
|
||||
} else {
|
||||
var focused = editors[msg.panel];
|
||||
focused.focus();
|
||||
focused.setSelection({ line: msg.line, ch: msg.ch });
|
||||
$(document).trigger('codeChange'); // does this bubble to our send function?
|
||||
}
|
||||
},
|
||||
error: function (data) {
|
||||
console.log('error in forbind', data);
|
||||
}
|
||||
});
|
||||
|
||||
function updateCode(msg, lang) {
|
||||
var diff, patch, result, code;
|
||||
|
||||
if (msg.text) {
|
||||
if (msg.diff) {
|
||||
diff = new diff_match_patch();
|
||||
code = editors[lang].getCode();
|
||||
console.log(msg.text);
|
||||
var patch = diff.patch_fromText(msg.text);
|
||||
var result = diff.patch_apply(patch, code);
|
||||
editors[lang].setCode(result[0]);
|
||||
} else {
|
||||
editors[lang].setCode(msg.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateCount(data) {
|
||||
if (owner) {
|
||||
var txt = (data.total - 1) == 1 ? ' user' : ' users';
|
||||
$stream.find('.n').html((data.total - 1) + txt);
|
||||
}
|
||||
}
|
||||
|
||||
window.stream = global.stream = {
|
||||
create: function () {
|
||||
key = (Math.abs(~~(Math.random()*+new Date))).toString(32); // OTT?
|
||||
|
||||
forbind.create(key);
|
||||
forbind.create(key);
|
||||
|
||||
return key;
|
||||
},
|
||||
join: function (key) {
|
||||
forbind.join(key);
|
||||
return key;
|
||||
},
|
||||
join: function (key) {
|
||||
forbind.join(key);
|
||||
|
||||
owner = false;
|
||||
sessionStorage.removeItem('streamkey');
|
||||
sessionStorage.removeItem('streamwritekey');
|
||||
owner = false;
|
||||
sessionStorage.removeItem('streamkey');
|
||||
sessionStorage.removeItem('streamwritekey');
|
||||
|
||||
$stream.addClass('listen');
|
||||
$stream.addClass('listen');
|
||||
|
||||
$(document).one('keyup', function (event) {
|
||||
if (streaming && event.which == 27) {
|
||||
$(document).one('keyup', function (event) {
|
||||
if (streaming && event.which == 27) {
|
||||
global.stream.leave();
|
||||
}
|
||||
});
|
||||
|
||||
$stream.one('click', function () {
|
||||
global.stream.leave();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$stream.one('click', function () {
|
||||
global.stream.leave();
|
||||
});
|
||||
|
||||
for (var type in editors) {
|
||||
try {
|
||||
$(editors[type].win.document).one('keyup', function (event) {
|
||||
if (event.which == 27) {
|
||||
global.stream.leave();
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// because it sometimes throw an error on reconnecting trying to read win.document
|
||||
for (var type in editors) {
|
||||
try {
|
||||
$(editors[type].win.document).one('keyup', function (event) {
|
||||
if (event.which == 27) {
|
||||
global.stream.leave();
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
// because it sometimes throw an error on reconnecting trying to read win.document
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$stream.find('.msg').html('following live stream...');
|
||||
},
|
||||
leave: function () {
|
||||
forbind.leave();
|
||||
$stream.find('.msg').html('following live stream...');
|
||||
},
|
||||
leave: function () {
|
||||
forbind.leave();
|
||||
}
|
||||
};
|
||||
|
||||
window.location.search.replace(/stream=(.+?)\b/, function (n, key) {
|
||||
global.stream.join(key);
|
||||
});
|
||||
|
||||
if (sessionStorage.getItem('streamkey')) {
|
||||
key = sessionStorage.getItem('streamkey');
|
||||
forbind.join(key, sessionStorage.getItem('streamwritekey') || undefined);
|
||||
}
|
||||
};
|
||||
|
||||
window.location.search.replace(/stream=(.+?)\b/, function (n, key) {
|
||||
global.stream.join(key);
|
||||
});
|
||||
|
||||
if (sessionStorage.getItem('streamkey')) {
|
||||
key = sessionStorage.getItem('streamkey');
|
||||
forbind.join(key, sessionStorage.getItem('streamwritekey') || undefined);
|
||||
}
|
||||
|
||||
})(this);
|
||||
}
|
||||
15
js/chrome/tips.js
Normal file
15
js/chrome/tips.js
Normal file
@ -0,0 +1,15 @@
|
||||
var $html = $(document.documentElement);
|
||||
|
||||
$('#tip a.dismiss').click(function () {
|
||||
$html.removeClass('showtip');
|
||||
$(window).resize();
|
||||
sessionStorage.setItem('tips', 'false');
|
||||
return false;
|
||||
});
|
||||
|
||||
var showTips = sessionStorage.getItem('tips');
|
||||
if (showTips === null) {
|
||||
// $html.addClass('showtip');
|
||||
}
|
||||
|
||||
// remove this setting after a few days (or a new set of tips come in)
|
||||
190
js/editors/autocomplete.js
Normal file
190
js/editors/autocomplete.js
Normal file
@ -0,0 +1,190 @@
|
||||
// Minimal event-handling wrapper.
|
||||
function stopEvent() {
|
||||
if (this.preventDefault) {this.preventDefault(); this.stopPropagation();}
|
||||
else {this.returnValue = false; this.cancelBubble = true;}
|
||||
}
|
||||
function addStop(event) {
|
||||
if (!event.stop) event.stop = stopEvent;
|
||||
return event;
|
||||
}
|
||||
function connect(node, type, handler) {
|
||||
function wrapHandler(event) {handler(addStop(event || window.event));}
|
||||
if (typeof node.addEventListener == "function")
|
||||
node.addEventListener(type, wrapHandler, false);
|
||||
else
|
||||
node.attachEvent("on" + type, wrapHandler);
|
||||
}
|
||||
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function startTagComplete(editor) {
|
||||
// We want a single cursor position.
|
||||
if (editor.somethingSelected()) return;
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(false), token = editor.getTokenAt(cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == "." ? "js-property" : null};
|
||||
}
|
||||
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.className == "js-property") {
|
||||
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
|
||||
if (tprop.string != ".") return;
|
||||
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
editor.replaceRange(str, {line: cur.line, ch: token.start}, {line: cur.line, ch: token.end});
|
||||
}
|
||||
|
||||
insert('<></>');
|
||||
editor.focus();
|
||||
editor.setCursor({ line: cur.line, ch: token.end });
|
||||
return true;
|
||||
}
|
||||
|
||||
function startComplete(editor) {
|
||||
// We want a single cursor position.
|
||||
if (editor.somethingSelected()) return;
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(false), token = editor.getTokenAt(cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
|
||||
if (token.string == '') return;
|
||||
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == "." ? "js-property" : null};
|
||||
}
|
||||
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.className == "js-property") {
|
||||
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
|
||||
if (tprop.string != ".") return;
|
||||
tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
|
||||
if (token.string == '' && context === undefined) return;
|
||||
|
||||
var completions = getCompletions(token, context, editor);
|
||||
if (!completions.length) return;
|
||||
function insert(str) {
|
||||
editor.replaceRange(str, {line: cur.line, ch: token.start}, {line: cur.line, ch: token.end});
|
||||
}
|
||||
// When there is only one completion, use it directly.
|
||||
if (completions.length == 1) {insert(completions[0]); return true;}
|
||||
|
||||
// Build the select widget
|
||||
var complete = document.createElement("div");
|
||||
complete.className = "completions";
|
||||
var sel = complete.appendChild(document.createElement("select"));
|
||||
sel.multiple = true;
|
||||
for (var i = 0; i < completions.length; ++i) {
|
||||
var opt = sel.appendChild(document.createElement("option"));
|
||||
opt.appendChild(document.createTextNode(completions[i]));
|
||||
}
|
||||
sel.firstChild.selected = true;
|
||||
sel.size = Math.min(10, completions.length);
|
||||
var pos = editor.cursorCoords();
|
||||
complete.style.left = pos.x + "px";
|
||||
complete.style.top = pos.yBot + "px";
|
||||
complete.style.position = 'absolute';
|
||||
complete.style.outline = 'none';
|
||||
complete.className = 'autocomplete';
|
||||
document.body.appendChild(complete);
|
||||
|
||||
// Hack to hide the scrollbar.
|
||||
if (completions.length <= 10) {
|
||||
complete.style.width = (sel.clientWidth - 1) + "px";
|
||||
}
|
||||
|
||||
var done = false;
|
||||
function close() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
complete.parentNode.removeChild(complete);
|
||||
}
|
||||
function pick() {
|
||||
insert(sel.options[sel.selectedIndex].value);
|
||||
close();
|
||||
setTimeout(function(){editor.focus();}, 50);
|
||||
}
|
||||
|
||||
function pickandclose() {
|
||||
pick()
|
||||
setTimeout(function () { editor.focus(); }, 50);
|
||||
}
|
||||
|
||||
connect(sel, "blur", close);
|
||||
connect(sel, "keydown", function(event) {
|
||||
var code = event.keyCode;
|
||||
// Enter and space
|
||||
if (code == 13 || code == 32) { event.stop(); pick();}
|
||||
// Escape
|
||||
else if (code == 27) {event.stop(); close(); editor.focus();}
|
||||
else if (code != 38 && code != 40) {close(); editor.focus(); setTimeout(function () { startComplete(editor) }, 50);}
|
||||
});
|
||||
connect(sel, "dblclick", pick);
|
||||
|
||||
sel.focus();
|
||||
// Opera sometimes ignores focusing a freshly created node
|
||||
if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||
var funcProps = "prototype apply call bind".split(" ");
|
||||
var keywords = ("break case catch continue debugger default delete do else false finally for function " +
|
||||
"if in instanceof new null return switch throw true try typeof var void while with").split(" ");
|
||||
|
||||
function getCompletions(token, context, editor) {
|
||||
var found = [], start = token.string;
|
||||
function maybeAdd(str) {
|
||||
if (str && str != start && str.indexOf(start) == 0 && found.indexOf(str) === -1) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
for (var name in obj) maybeAdd(name);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.className == "js-variable")
|
||||
base = window[obj.string];
|
||||
else if (obj.className == "js-string")
|
||||
base = "";
|
||||
else if (obj.className == "js-atom")
|
||||
base = 1;
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
}
|
||||
else {
|
||||
// If not, just look in the window object and any local scope
|
||||
// (reading into JS mode internals to get at the local variables)
|
||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||
gatherCompletions(window);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
|
||||
// also look up symbols in the current document
|
||||
var code = editor.getValue().split(/\W/);
|
||||
forEach(code, maybeAdd);
|
||||
|
||||
return found;
|
||||
}
|
||||
@ -1,12 +1,18 @@
|
||||
// used to generate the ../vendor/codemirror/basefiles.js
|
||||
//= require "../vendor/codemirror/util"
|
||||
//= require "../vendor/codemirror/stringstream"
|
||||
//= require "../vendor/codemirror/undo"
|
||||
//= require "../vendor/codemirror/editor"
|
||||
//= require "../vendor/codemirror/tokenize"
|
||||
//= require "../vendor/codemirror/select"
|
||||
//= require "../vendor/codemirror/parsexml"
|
||||
//= require "../vendor/codemirror/parsecss"
|
||||
//= require "../vendor/codemirror/tokenizejavascript"
|
||||
//= require "../vendor/codemirror/parsejavascript"
|
||||
//= require "../vendor/codemirror/parsehtmlmixed"
|
||||
// = require "../vendor/codemirror/util"
|
||||
// = require "../vendor/codemirror/stringstream"
|
||||
// = require "../vendor/codemirror/undo"
|
||||
// = require "../vendor/codemirror/editor"
|
||||
// = require "../vendor/codemirror/tokenize"
|
||||
// = require "../vendor/codemirror/select"
|
||||
// = require "../vendor/codemirror/parsexml"
|
||||
// = require "../vendor/codemirror/parsecss"
|
||||
// = require "../vendor/codemirror/tokenizejavascript"
|
||||
// = require "../vendor/codemirror/parsejavascript"
|
||||
// = require "../vendor/codemirror/parsehtmlmixed"
|
||||
|
||||
//= require "../vendor/codemirror2/codemirror"
|
||||
//= require "../vendor/codemirror2/xml"
|
||||
//= require "../vendor/codemirror2/css"
|
||||
//= require "../vendor/codemirror2/javascript"
|
||||
//= require "../vendor/codemirror2/htmlmixed"
|
||||
|
||||
@ -1,68 +1,62 @@
|
||||
//= require <codemirror>
|
||||
// = require <codemirror>
|
||||
//= require "codemirror"
|
||||
//= require "mobileCodeMirror"
|
||||
//= require "library"
|
||||
//= require "unsaved"
|
||||
//= require "autocomplete"
|
||||
var focusPanel = 'javascript';
|
||||
var editors = {};
|
||||
editors.html = CodeMirror.fromTextArea('html', {
|
||||
basefiles: ['basefiles.js'],
|
||||
|
||||
window.editors = editors;
|
||||
|
||||
editors.html = CodeMirror.fromTextArea(document.getElementById('html'), {
|
||||
parserfile: [],
|
||||
stylesheet: ["/css/codemirror.css", "/css/htmlcodeframe.css"],
|
||||
path: '/js/vendor/codemirror/',
|
||||
tabMode: 'shift',
|
||||
iframeClass: 'stretch codeframe',
|
||||
initCallback: function () {
|
||||
setupEditor('html');
|
||||
}
|
||||
mode: 'text/html',
|
||||
onChange: changecontrol,
|
||||
theme: jsbin.settings.theme
|
||||
});
|
||||
|
||||
editors.javascript = CodeMirror.fromTextArea('javascript', {
|
||||
basefiles: ['basefiles.js'],
|
||||
parserfile: ['parsejavascript.js'], // forces a switch back to JS parsing
|
||||
stylesheet: ["/css/codemirror.css", "/css/codeframe.css"],
|
||||
path: '/js/vendor/codemirror/',
|
||||
iframeClass: 'stretch codeframe javascript',
|
||||
editors.javascript = CodeMirror.fromTextArea(document.getElementById('javascript'), {
|
||||
mode: 'javascript',
|
||||
tabMode: 'shift',
|
||||
initCallback: function () {
|
||||
setupEditor('javascript');
|
||||
}
|
||||
onChange: changecontrol,
|
||||
theme: jsbin.settings.theme
|
||||
});
|
||||
|
||||
setupEditor('javascript');
|
||||
setupEditor('html');
|
||||
|
||||
var editorsReady = setInterval(function () {
|
||||
if (editors.html.ready && editors.javascript.ready) {
|
||||
clearInterval(editorsReady);
|
||||
editors.ready = true;
|
||||
if (typeof editors.onReady == 'function') editors.onReady();
|
||||
$(document).trigger('jsbinReady');
|
||||
|
||||
$document.bind('sizeeditors', function () {
|
||||
var $el = $(editors.html.win),
|
||||
top = 0, //$el.offset().top,
|
||||
height = $('#bin').height();
|
||||
$el.height(height - top);
|
||||
$(editors.javascript.win).height(height - top - $error.filter(':visible').height());
|
||||
editors.javascript.refresh();
|
||||
editors.html.refresh();
|
||||
});
|
||||
|
||||
$(window).resize(function () {
|
||||
setTimeout(function () {
|
||||
$document.trigger('sizeeditors');
|
||||
}, 100);
|
||||
});
|
||||
|
||||
$document.trigger('sizeeditors');
|
||||
$document.trigger('jsbinReady');
|
||||
}
|
||||
}, 100);
|
||||
|
||||
var oninputSupported = (function () {
|
||||
var input = document.createElement('input');
|
||||
var support = "oninput" in input && "A";
|
||||
if ( !support ) {
|
||||
input.setAttribute("oninput", "return;");
|
||||
support = typeof input.oninput === "function" && "B";
|
||||
}
|
||||
if ( !support ) {
|
||||
try {
|
||||
var e = document.createEvent("KeyboardEvent");
|
||||
e.initKeyEvent("keypress", true, true, window, false, false, false, false, 0, "e".charCodeAt(0));
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener("input", function(e) { support = "C"; e.preventDefault(); e.stopPropagation(); }, false);
|
||||
input.focus();
|
||||
input.dispatchEvent(e);
|
||||
document.body.removeChild(input);
|
||||
} catch( e ) {}
|
||||
}
|
||||
})();
|
||||
|
||||
function focused(event) {
|
||||
focusPanel = this.id;
|
||||
$('#bin').toggleClass('javascript', this.id == 'javascript');
|
||||
$(editors.html.win.document).find('body').removeClass('focus');
|
||||
$(editors.javascript.win.document).find('body').removeClass('focus');
|
||||
$(this).find('body').addClass('focus');
|
||||
function focused(editor, event) {
|
||||
focusPanel = editor.id;
|
||||
}
|
||||
|
||||
function getFocusedPanel() {
|
||||
@ -73,18 +67,36 @@ function setupEditor(panel) {
|
||||
var e = editors[panel],
|
||||
focusedPanel = sessionStorage.getItem('panel');
|
||||
|
||||
e.wrapping.style.position = 'static';
|
||||
e.wrapping.style.height = 'auto';
|
||||
|
||||
e.win.document.id = panel;
|
||||
$(e.win.document).bind('keydown', keycontrol);
|
||||
$(e.win.document).bind(oninputSupported ? 'input' : 'keyup', changecontrol);
|
||||
$(e.win.document).focus(focused);
|
||||
// overhang from CodeMirror1
|
||||
e.setCode = function (str) {
|
||||
e.setValue(str);
|
||||
};
|
||||
|
||||
e.getCode = function () {
|
||||
return e.getValue();
|
||||
};
|
||||
|
||||
e.currentLine = function () {
|
||||
var pos = e.getCursor();
|
||||
return pos.line;
|
||||
};
|
||||
|
||||
e.setOption('onChange', changecontrol);
|
||||
e.setOption('onKeyEvent', keycontrol);
|
||||
e.setOption('onFocus', focused);
|
||||
|
||||
e.id = panel;
|
||||
|
||||
e.win = e.getWrapperElement();
|
||||
|
||||
$(e.win).click(function () {
|
||||
e.focus();
|
||||
});
|
||||
|
||||
var $label = $('.code.' + panel + ' > .label');
|
||||
if (document.body.className.indexOf('ie6') === -1) {
|
||||
$(e.win.document).bind('scroll', function (event) {
|
||||
if (this.body.scrollTop > 10) {
|
||||
e.setOption('onScroll', function (event) {
|
||||
if (e.win.scrollTop > 10) {
|
||||
$label.stop().animate({ opacity: 0 }, 50, function () {
|
||||
$(this).hide();
|
||||
});
|
||||
@ -98,18 +110,20 @@ function setupEditor(panel) {
|
||||
e.ready = true;
|
||||
|
||||
if (focusedPanel == panel || focusedPanel == null && panel == 'javascript') {
|
||||
// e.selectLines(e.nthLine(sessionStorage.getItem('line')), sessionStorage.getItem('character'));
|
||||
e.focus();
|
||||
e.selectLines(e.nthLine(sessionStorage.getItem('line')), sessionStorage.getItem('character'));
|
||||
e.setCursor({ line: (sessionStorage.getItem('line') || 0) * 1, ch: (sessionStorage.getItem('character') || 0) * 1 });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function populateEditor(panel) {
|
||||
// populate - should eventually use: session, saved data, local storage
|
||||
var data = sessionStorage.getItem(panel), // session code
|
||||
saved = localStorage.getItem('saved-' + panel), // user template
|
||||
sessionURL = sessionStorage.getItem('url'),
|
||||
changed = false;
|
||||
|
||||
|
||||
if (data == template[panel]) { // restored from original saved
|
||||
editors[panel].setCode(data);
|
||||
} else if (data && sessionURL == template.url) { // try to restore the session first - only if it matches this url
|
||||
@ -164,33 +178,94 @@ function accessKey(event) {
|
||||
return on;
|
||||
}
|
||||
|
||||
function keycontrol(event) {
|
||||
var ctrl = accessKey(event);
|
||||
|
||||
if (ctrl && event.which == 39 && this.id == 'javascript') {
|
||||
function keycontrol(panel, event) {
|
||||
var ctrl = event.ctrlKey; //accessKey(event);
|
||||
|
||||
if (ctrl && event.which == 39 && panel.id == 'javascript') {
|
||||
// go right
|
||||
editors.html.focus();
|
||||
return false;
|
||||
} else if (ctrl && event.which == 37 && this.id == 'html') {
|
||||
event.stop();
|
||||
} else if (ctrl && event.which == 37 && panel.id == 'html') {
|
||||
// go left
|
||||
editors.javascript.focus();
|
||||
return false;
|
||||
event.stop();
|
||||
} else if (ctrl && event.which == 49) { // 49 == 1 key
|
||||
$('#control a.source').click();
|
||||
return false;
|
||||
event.stop();
|
||||
} else if (event.which == 191 && event.shiftKey && event.metaKey) {
|
||||
// show help
|
||||
console.log('showing help - TBI');
|
||||
event.stop();
|
||||
} else if (ctrl && event.which == 50) {
|
||||
$('#control a.preview').click();
|
||||
return false;
|
||||
event.stop();
|
||||
} else if (event.which == 27) {
|
||||
event.stop();
|
||||
return startComplete(panel);
|
||||
} else if (event.which == 190 && event.altKey && event.metaKey && panel.id == 'html') {
|
||||
// auto close the element
|
||||
if (panel.somethingSelected()) return;
|
||||
// Find the token at the cursor
|
||||
var cur = panel.getCursor(false), token = panel.getTokenAt(cur), tprop = token;
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
className: token.string == "." ? "js-property" : null};
|
||||
}
|
||||
|
||||
panel.replaceRange('</' + token.state.htmlState.context.tagName + '>', {line: cur.line, ch: token.end}, {line: cur.line, ch: token.end});
|
||||
event.stop();
|
||||
} else if (event.which == 188 && event.ctrlKey && event.shiftKey) {
|
||||
// start a new tag
|
||||
event.stop();
|
||||
return startTagComplete(panel);
|
||||
} else if (event.which == 191 && event.metaKey) {
|
||||
// auto close the element
|
||||
if (panel.somethingSelected()) return;
|
||||
|
||||
var cur = panel.getCursor(false),
|
||||
token = panel.getTokenAt(cur),
|
||||
type = token && token.state && token.state.token ? token.state.token.name : 'javascript',
|
||||
line = panel.getLine(cur.line);
|
||||
|
||||
if (type == 'css') {
|
||||
if (line.match(/\s*\/\*/) !== null) {
|
||||
// already contains comment - remove
|
||||
panel.setLine(cur.line, line.replace(/\/\*\s?/, '').replace(/\s?\*\//, ''));
|
||||
} else {
|
||||
// panel.replaceRange('// ', {line: cur.line, ch: 0}, {line: cur.line, ch: 0});
|
||||
panel.setLine(cur.line, '/* ' + line + ' */');
|
||||
}
|
||||
} else if (type == 'javascript') {
|
||||
// FIXME - could put a JS comment next to a <script> tag
|
||||
if (line.match(/\s*\/\//) !== null) {
|
||||
// already contains comment - remove
|
||||
panel.setLine(cur.line, line.replace(/(\s*)\/\/\s?/, '$1'));
|
||||
} else {
|
||||
// panel.replaceRange('// ', {line: cur.line, ch: 0}, {line: cur.line, ch: 0});
|
||||
panel.setLine(cur.line, '// ' + line);
|
||||
}
|
||||
} else if (type == 'html') {
|
||||
if (line.match(/\s*<!--/) !== null) {
|
||||
// already contains comment - remove
|
||||
panel.setLine(cur.line, line.replace(/<!--\s?/, '').replace(/\s?-->/, ''));
|
||||
} else {
|
||||
// panel.replaceRange('// ', {line: cur.line, ch: 0}, {line: cur.line, ch: 0});
|
||||
panel.setLine(cur.line, '<!-- ' + line + ' -->');
|
||||
}
|
||||
}
|
||||
|
||||
event.stop();
|
||||
}
|
||||
|
||||
return true;
|
||||
// return true;
|
||||
}
|
||||
|
||||
function changecontrol(event) {
|
||||
// sends message to the document saying that a key has been pressed, we'll ignore the control keys
|
||||
if (! ({ 16:1, 17:1, 18:1, 20:1, 27:1, 37:1, 38:1, 39:1, 40:1, 91:1, 93:1 })[event.which] ) {
|
||||
// if (! ({ 16:1, 17:1, 18:1, 20:1, 27:1, 37:1, 38:1, 39:1, 40:1, 91:1, 93:1 })[event.which] ) {
|
||||
$(document).trigger('codeChange');
|
||||
}
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,8 +43,8 @@ Libraries.prototype.init = function () {
|
||||
scripts: [
|
||||
{ text: 'jQuery latest', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js' },
|
||||
{ text: 'jQuery WIP (via git)', url: 'http://code.jquery.com/jquery-git.js' },
|
||||
{ text: 'jQuery 1.5.2', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js' },
|
||||
{ text: 'jQuery 1.4.4', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js' }
|
||||
{ text: 'jQuery 1.5.2', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js' },
|
||||
{ text: 'jQuery 1.4.4', url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js' }
|
||||
]
|
||||
},
|
||||
jqueryui : {
|
||||
@ -66,8 +66,9 @@ Libraries.prototype.init = function () {
|
||||
others: {
|
||||
text: 'Others',
|
||||
scripts: [
|
||||
{ text: 'underscore', url: 'http://documentcloud.github.com/underscore/underscore-min.js'},
|
||||
{ text: 'Raphaël', url: 'https://github.com/DmitryBaranovskiy/raphael/raw/master/raphael-min.js'}
|
||||
{ text: 'Modernizr', url: 'http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.0.4/modernizr.min.js'},
|
||||
{ text: 'underscore', url: 'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.1.6/underscore-min.js'},
|
||||
{ text: 'Raphaël', url: 'http://cdnjs.cloudflare.com/ajax/libs/raphael/1.5.2/raphael-min.js'}
|
||||
]
|
||||
},
|
||||
scriptaculous: {
|
||||
|
||||
@ -16,23 +16,28 @@ $('#library').bind('init', function () {
|
||||
$select.html( html.join('') ).val(selected);
|
||||
}).trigger('init');
|
||||
|
||||
var state = {};
|
||||
|
||||
$('#library').bind('change', function () {
|
||||
var libIndex = [],
|
||||
lib = {},
|
||||
state = {},
|
||||
re,
|
||||
i,
|
||||
code = editors.html.getCode();
|
||||
|
||||
// strip existing libraries out
|
||||
var addAdjust = code.match(/<(script|link) class="jsbin"/g);
|
||||
if (addAdjust == null) addAdjust = [];
|
||||
|
||||
code = code.replace(/<script class="jsbin".*><\/script>\n?/g, '');
|
||||
code = code.replace(/<link class="jsbin".*\/>\n?/g, '');
|
||||
|
||||
if (this.value != 'none') {
|
||||
// to restore
|
||||
// to restore (note - the adjustment isn't quite 100% right yet)
|
||||
state = {
|
||||
line: editors.html.currentLine(),
|
||||
character: editors.html.cursorPosition().character
|
||||
character: editors.html.getCursor().ch,
|
||||
add: 1 - addAdjust.length
|
||||
};
|
||||
|
||||
libIndex = this.value.split('-');
|
||||
@ -41,15 +46,21 @@ $('#library').bind('change', function () {
|
||||
// all has to happen in reverse order because we're going directly after <head>
|
||||
code = code.replace('<head', "<head>\n<" + 'script class="jsbin" src="' + lib.scripts[libIndex[1]].url + '"><' + '/script');
|
||||
if (lib.requires) {
|
||||
state.add++;
|
||||
code = code.replace('<head', "<head>\n<" + 'script class="jsbin" src="' + lib.requires + '"><' + '/script');
|
||||
}
|
||||
|
||||
if (lib.style) {
|
||||
state.add++;
|
||||
code = code.replace('<head', "<head>\n<" + 'link class="jsbin" href="' + lib.style + '" rel="stylesheet" type="text/css" /');
|
||||
}
|
||||
|
||||
state.line += state.add;
|
||||
} else {
|
||||
state.line -= state.add;
|
||||
}
|
||||
|
||||
editors.html.setCode(code);
|
||||
editors.html.focus();
|
||||
editors.html.selectLines(editors.html.nthLine(state.line), state.character);
|
||||
editors.html.setCursor({ line: state.line, ch: state.character });
|
||||
});
|
||||
@ -6,9 +6,14 @@ $(document).bind('codeChange', function (event, revert, onload) {
|
||||
$revert.removeClass('enable');
|
||||
}
|
||||
|
||||
updateTitle(revert, onload);
|
||||
});
|
||||
|
||||
function updateTitle(revert, onload) {
|
||||
var title = !documentTitle ? 'JS Bin' : documentTitle;
|
||||
if (!revert && !/\*$/.test(document.title)) {
|
||||
if (/debug/i.test(document.title)) {
|
||||
document.title = 'JS Bin - [unsaved]';
|
||||
document.title = title + ' - [unsaved]';
|
||||
}
|
||||
document.title += '*';
|
||||
|
||||
@ -17,5 +22,7 @@ $(document).bind('codeChange', function (event, revert, onload) {
|
||||
}
|
||||
} else if (revert && /\*$/.test(document.title)) {
|
||||
document.title = document.title.replace(/\*$/, '');
|
||||
} else {
|
||||
document.title = title;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
16
js/jsbin.js
16
js/jsbin.js
@ -5,7 +5,23 @@ jQuery.expr[':'].host = function(obj, index, meta, stack) {
|
||||
return obj.host == meta[3];
|
||||
};
|
||||
|
||||
// jQuery plugins
|
||||
//= require "chrome/splitter"
|
||||
|
||||
(function (window, document, undefined) {
|
||||
function throttle(fn, delay) {
|
||||
var timer = null;
|
||||
return function () {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(context, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
//= require "chrome/storage"
|
||||
window.jsbin.settings = JSON.parse(localStorage.getItem('settings') || '{ "show": { "html": true, "javascript": true }, "theme": "default" }');
|
||||
//= require "vendor/json2"
|
||||
//= require "editors/editors"
|
||||
//= require "render/render"
|
||||
//= require "chrome/beta"
|
||||
|
||||
@ -16,7 +16,7 @@ ConsoleContext.prototype = {
|
||||
var context = this.executable ? this.context() : this.context;
|
||||
var re = new RegExp('console\.' + method + '\\((.*?)\\)');
|
||||
// if the log was triggered via a jQuery.Event then it came from /within/ the preview
|
||||
if (!(arguments.callee.caller.caller.arguments[0] instanceof jQuery.Event) && context) {
|
||||
if (arguments.callee.caller.caller.arguments.length > 0 && !(arguments.callee.caller.caller.arguments[0] instanceof jQuery.Event) && context) {
|
||||
context.eval('console.' + method + '(' + arguments.callee.caller.caller.arguments[0].toString().match(re)[1] + ')');
|
||||
} else {
|
||||
this.original[method].apply(this.original, args);
|
||||
@ -51,4 +51,4 @@ ConsoleContext.prototype = {
|
||||
window.top.console = this.original;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -24,7 +24,7 @@
|
||||
|
||||
var el = document.createElement('a');
|
||||
|
||||
set(el, { opacity: 0, position: 'fixed', top: 0, right: 0, padding: '5px', background: '#eee', color: '#212121', 'border-bottom-left-radius': '10px', MozBorderRadiusBottomleft: '10px', border: '1px solid #999', borderRight: 0, borderTop: 0, textDecoration: 'none', font: '12px "Helvetica Neue", Arial, Helvetica' });
|
||||
set(el, { opacity: 0, position: 'fixed', top: 0, right: 0, padding: '5px', background: '#eee url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAYAAADtlXTHAAAAM0lEQVQIHWM4c+bMf6Z///4xMP39+5eB6f///wwQLlgMjYsQwykBVoIg0NShcbGZB3IGAKmKWgUE0gb7AAAAAElFTkSuQmCC) repeat-x', color: '#000', 'text-shadow': '0px -1px 0 #ccc', 'border-bottom-left-radius': '10px', MozBorderRadiusBottomleft: '10px', border: '1px solid #999', borderRight: 0, borderTop: 0, textDecoration: 'none', font: '12px "Helvetica Neue", Arial, Helvetica' });
|
||||
el.innerHTML = 'Edit using JS Bin';
|
||||
el.href = window.location.pathname + (window.location.pathname.substr(-1) == '/' ? '' : '/') + 'edit';
|
||||
|
||||
|
||||
@ -1,36 +1,46 @@
|
||||
var $live = $('#live'),
|
||||
$body = $('body'),
|
||||
throttledPreview = throttle(renderLivePreview, 100);
|
||||
showlive = $('#showlive')[0],
|
||||
throttledPreview = throttle(renderLivePreview, 200);
|
||||
|
||||
//= require "consoleContext"
|
||||
var hijackedConsole = new ConsoleContext(function () {
|
||||
return $('#live iframe').length ? $('#live iframe')[0].contentWindow : null;
|
||||
});
|
||||
|
||||
$body.delegate('#control .button.live', 'click', function () {
|
||||
$live.trigger('toggle');
|
||||
});
|
||||
///= require "consoleContext"
|
||||
// var hijackedConsole = new ConsoleContext(function () {
|
||||
// return $('#live iframe').length ? $('#live iframe')[0].contentWindow : null;
|
||||
// });
|
||||
|
||||
// could chain - but it's more readable like this
|
||||
$live.bind('show', function () {
|
||||
// hijackedConsole.activate();
|
||||
$body.addClass('live');
|
||||
showlive.checked = true;
|
||||
localStorage && localStorage.setItem('livepreview', true);
|
||||
|
||||
var data = $live.data();
|
||||
if (data.splitter) {
|
||||
data.splitter.show().trigger('init');
|
||||
}
|
||||
// start timer
|
||||
$(document).bind('codeChange.live', throttledPreview);
|
||||
renderLivePreview();
|
||||
//hijackedConsole.activate();
|
||||
}).bind('hide', function () {
|
||||
// hijackedConsole.deactivate();
|
||||
$(document).unbind('codeChange.live');
|
||||
localStorage && localStorage.removeItem('livepreview');
|
||||
$body.removeClass('live');
|
||||
//hijackedConsole.deactivate();
|
||||
showlive.checked = false;
|
||||
|
||||
$('#source').css('right', 0);
|
||||
|
||||
var data = $live.data();
|
||||
if (data.splitter) {
|
||||
data.splitter.hide();
|
||||
}
|
||||
}).bind('toggle', function () {
|
||||
$live.trigger($body.is('.live') ? 'hide' : 'show');
|
||||
});
|
||||
|
||||
function enableLive() {
|
||||
$('#control .buttons .preview').after('<a id="showlive" class="button live group right left light gap" href="#">Live</a>');
|
||||
// $('#control .buttons .preview').after('<a id="showlive" class="button live group right left light gap" href="#">Live</a>');
|
||||
}
|
||||
|
||||
function two(s) {
|
||||
@ -38,10 +48,10 @@ function two(s) {
|
||||
}
|
||||
|
||||
function renderLivePreview() {
|
||||
var oldframe = $live.find('iframe').remove();
|
||||
var frame = $live.append('<iframe class="stretch"></iframe>').find('iframe')[0],
|
||||
var source = getPreparedCode(),
|
||||
oldframe = $live.find('iframe').remove(),
|
||||
frame = $live.append('<iframe class="stretch"></iframe>').find('iframe')[0],
|
||||
document = frame.contentDocument || frame.contentWindow.document,
|
||||
source = getPreparedCode(),
|
||||
window = document.defaultView || document.parentWindow,
|
||||
d = new Date();
|
||||
|
||||
@ -49,9 +59,13 @@ function renderLivePreview() {
|
||||
window.alert = function () {};
|
||||
window.prompt = function () {};
|
||||
window.confirm = function () {};
|
||||
// window.XMLHttpRequest = function () {};
|
||||
|
||||
if (!useCustomConsole) console.log('--- refreshing live preview @ ' + [two(d.getHours()),two(d.getMinutes()),two(d.getSeconds())].join(':') + ' ---');
|
||||
|
||||
// strip autofocus from the markup - prevents the focus switching out of the editable area
|
||||
source = source.replace(/(<.*?\s)(autofocus)/g, '$1');
|
||||
|
||||
document.open();
|
||||
|
||||
if (debug) {
|
||||
@ -67,5 +81,5 @@ function renderLivePreview() {
|
||||
}
|
||||
|
||||
$live.find('.close').click(function () {
|
||||
$live.trigger('hide');
|
||||
updatePanel('live', false);
|
||||
});
|
||||
|
||||
@ -41,15 +41,29 @@ function getPreparedCode() {
|
||||
} else if (/%code%/.test(source)) {
|
||||
parts = source.split('%code%');
|
||||
source = parts[0] + js + parts[1];
|
||||
} else {
|
||||
} else if (js) {
|
||||
parts = source.split('</body>');
|
||||
source = parts[0] + "<script src=\"http://jsbin.com/js/render/console.js\"></script>\n<script>\ntry {\n" + js + "\n} catch (e) {" + (window.console === undefined ? '_' : 'window.top.') + "console.error(e)}\n</script>\n</body>" + parts[1];
|
||||
source = parts[0];
|
||||
|
||||
var close = parts.length == 2 ? '</body>' + parts[1] : '';
|
||||
|
||||
if (useCustomConsole) {
|
||||
source += "<script src=\"http://jsbin.com/js/render/console.js\"></script>\n<script>\n";
|
||||
}
|
||||
source += "<script>\ntry {\n" + js + "\n} catch (e) {" + (window.console === undefined ? '_' : 'window.top.') + "console.error(e)}\n</script>\n" + close;
|
||||
}
|
||||
|
||||
// specific change for rendering $(document).ready() because iframes doesn't trigger ready (TODO - really test in IE, may have been fixed...)
|
||||
if (/\$\(document\)\.ready/.test(source)) {
|
||||
source = source.replace(/\$\(document\)\.ready/, 'window.onload = ');
|
||||
}
|
||||
|
||||
// read the element out of the source code and plug it in to our document.title
|
||||
var newDocTitle = source.match(/<title>(.*)<\/title>/i);
|
||||
if (newDocTitle !== null && newDocTitle[1] !== documentTitle) {
|
||||
documentTitle = newDocTitle[1];
|
||||
updateTitle();
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
@ -71,4 +85,4 @@ function renderPreview() {
|
||||
win.write(source);
|
||||
}
|
||||
win.close();
|
||||
}
|
||||
}
|
||||
|
||||
2155
js/vendor/diff_match_patch_uncompressed.js
vendored
Normal file
2155
js/vendor/diff_match_patch_uncompressed.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user