Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
1856286f
Commit
1856286f
authored
Jul 04, 2013
by
Andrew Gerrand
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
doc: update playground.js
R=dsymonds CC=golang-dev
https://golang.org/cl/10933044
parent
dd1fe82c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
395 additions
and
260 deletions
+395
-260
doc/play/playground.js
doc/play/playground.js
+391
-259
doc/style.css
doc/style.css
+4
-1
No files found.
doc/play/playground.js
View file @
1856286f
...
...
@@ -2,295 +2,427 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// opts is an object with these keys
// codeEl - code editor element
// outputEl - program output element
// runEl - run button element
// fmtEl - fmt button element (optional)
// shareEl - share button element (optional)
// shareURLEl - share URL text input element (optional)
// shareRedirect - base URL to redirect to on share (optional)
// toysEl - toys select element (optional)
// enableHistory - enable using HTML5 history API (optional)
function
playground
(
opts
)
{
var
code
=
$
(
opts
[
'
codeEl
'
]);
// autoindent helpers.
function
insertTabs
(
n
)
{
// find the selection start and end
var
start
=
code
[
0
].
selectionStart
;
var
end
=
code
[
0
].
selectionEnd
;
// split the textarea content into two, and insert n tabs
var
v
=
code
[
0
].
value
;
var
u
=
v
.
substr
(
0
,
start
);
for
(
var
i
=
0
;
i
<
n
;
i
++
)
{
u
+=
"
\t
"
;
}
u
+=
v
.
substr
(
end
);
// set revised content
code
[
0
].
value
=
u
;
// reset caret position after inserted tabs
code
[
0
].
selectionStart
=
start
+
n
;
code
[
0
].
selectionEnd
=
start
+
n
;
}
function
autoindent
(
el
)
{
var
curpos
=
el
.
selectionStart
;
var
tabs
=
0
;
while
(
curpos
>
0
)
{
curpos
--
;
if
(
el
.
value
[
curpos
]
==
"
\t
"
)
{
tabs
++
;
}
else
if
(
tabs
>
0
||
el
.
value
[
curpos
]
==
"
\n
"
)
{
break
;
}
}
setTimeout
(
function
()
{
insertTabs
(
tabs
);
},
1
);
}
// This is a copy of present/js/playground.js from the repository at
// https://code.google.com/p/go.talks
// Please make changes to that repository.
function
keyHandler
(
e
)
{
if
(
e
.
keyCode
==
9
)
{
// tab
insertTabs
(
1
);
e
.
preventDefault
();
return
false
;
}
if
(
e
.
keyCode
==
13
)
{
// enter
if
(
e
.
shiftKey
)
{
// +shift
run
();
e
.
preventDefault
();
return
false
;
}
else
{
autoindent
(
e
.
target
);
}
}
return
true
;
}
code
.
unbind
(
'
keydown
'
).
bind
(
'
keydown
'
,
keyHandler
);
var
output
=
$
(
opts
[
'
outputEl
'
]);
/*
In the absence of any formal way to specify interfaces in JavaScript,
here's a skeleton implementation of a playground transport.
function
body
()
{
return
$
(
opts
[
'
codeEl
'
]).
val
();
}
function
setBody
(
text
)
{
$
(
opts
[
'
codeEl
'
]).
val
(
text
);
}
function
origin
(
href
)
{
return
(
""
+
href
).
split
(
"
/
"
).
slice
(
0
,
3
).
join
(
"
/
"
);
}
function
loading
()
{
output
.
removeClass
(
"
error
"
).
html
(
'
<div class="loading">Waiting for remote server...</div>
'
);
}
var
playbackTimeout
;
function
playback
(
pre
,
events
)
{
function
show
(
msg
)
{
// ^L clears the screen.
var
msgs
=
msg
.
split
(
"
\
x0c
"
);
if
(
msgs
.
length
==
1
)
{
pre
.
text
(
pre
.
text
()
+
msg
);
return
;
}
pre
.
text
(
msgs
.
pop
());
}
function Transport() {
// Set up any transport state (eg, make a websocket connnection).
return {
Run: function(body, output, options) {
// Compile and run the program 'body' with 'options'.
// Call the 'output' callback to display program output.
return {
Kill: function() {
// Kill the running program.
}
};
}
};
}
// The output callback is called multiple times, and each time it is
// passed an object of this form.
var write = {
Kind: 'string', // 'start', 'stdout', 'stderr', 'end'
Body: 'string' // content of write or end status message
}
// The first call must be of Kind 'start' with no body.
// Subsequent calls may be of Kind 'stdout' or 'stderr'
// and must have a non-null Body string.
// The final call should be of Kind 'end' with an optional
// Body string, signifying a failure ("killed", for example).
// The output callback must be of this form.
// See PlaygroundOutput (below) for an implementation.
function outputCallback(write) {
}
*/
function
HTTPTransport
()
{
'
use strict
'
;
// TODO(adg): support stderr
function
playback
(
output
,
events
)
{
var
timeout
;
output
({
Kind
:
'
start
'
});
function
next
()
{
if
(
events
.
length
==
0
)
{
var
exit
=
$
(
'
<span class="exit"/>
'
);
exit
.
text
(
"
\n
Program exited.
"
);
exit
.
appendTo
(
pre
);
if
(
events
.
length
===
0
)
{
output
({
Kind
:
'
end
'
});
return
;
}
var
e
=
events
.
shift
();
if
(
e
.
Delay
==
0
)
{
show
(
e
.
Message
);
if
(
e
.
Delay
==
=
0
)
{
output
({
Kind
:
'
stdout
'
,
Body
:
e
.
Message
}
);
next
();
}
else
{
playbackTimeout
=
setTimeout
(
function
()
{
show
(
e
.
Message
);
next
();
},
e
.
Delay
/
1000000
);
return
;
}
timeout
=
setTimeout
(
function
()
{
output
({
Kind
:
'
stdout
'
,
Body
:
e
.
Message
});
next
();
},
e
.
Delay
/
1000000
);
}
next
();
}
function
stopPlayback
()
{
clearTimeout
(
playbackTimeout
);
}
function
setOutput
(
events
,
error
)
{
stopPlayback
();
output
.
empty
();
$
(
"
.lineerror
"
).
removeClass
(
"
lineerror
"
);
// Display errors.
if
(
error
)
{
output
.
addClass
(
"
error
"
);
var
regex
=
/prog.go:
([
0-9
]
+
)
/g
;
var
r
;
while
(
r
=
regex
.
exec
(
error
))
{
$
(
"
.lines div
"
).
eq
(
r
[
1
]
-
1
).
addClass
(
"
lineerror
"
);
return
{
Stop
:
function
()
{
clearTimeout
(
timeout
);
}
$
(
"
<pre/>
"
).
text
(
error
).
appendTo
(
output
);
return
;
}
}
// Display image output.
if
(
events
.
length
>
0
&&
events
[
0
].
Message
.
indexOf
(
"
IMAGE:
"
)
==
0
)
{
var
out
=
""
;
for
(
var
i
=
0
;
i
<
events
.
length
;
i
++
)
{
out
+=
events
[
i
].
Message
;
}
var
url
=
"
data:image/png;base64,
"
+
out
.
substr
(
6
);
$
(
"
<img/>
"
).
attr
(
"
src
"
,
url
).
appendTo
(
output
);
return
;
}
function
error
(
output
,
msg
)
{
output
({
Kind
:
'
start
'
});
output
({
Kind
:
'
stderr
'
,
Body
:
msg
});
output
({
Kind
:
'
end
'
});
}
// Play back events.
if
(
events
!==
null
)
{
var
pre
=
$
(
"
<pre/>
"
).
appendTo
(
output
);
playback
(
pre
,
events
);
var
seq
=
0
;
return
{
Run
:
function
(
body
,
output
,
options
)
{
seq
++
;
var
cur
=
seq
;
var
playing
;
$
.
ajax
(
'
/compile
'
,
{
type
:
'
POST
'
,
data
:
{
'
version
'
:
2
,
'
body
'
:
body
},
dataType
:
'
json
'
,
success
:
function
(
data
)
{
if
(
seq
!=
cur
)
return
;
if
(
!
data
)
return
;
if
(
playing
!=
null
)
playing
.
Stop
();
if
(
data
.
Errors
)
{
error
(
output
,
data
.
Errors
);
return
;
}
playing
=
playback
(
output
,
data
.
Events
);
},
error
:
function
()
{
error
(
output
,
'
Error communicating with remote server.
'
);
}
});
return
{
Kill
:
function
()
{
if
(
playing
!=
null
)
playing
.
Stop
();
output
({
Kind
:
'
end
'
,
Body
:
'
killed
'
});
}
};
}
};
}
function
SocketTransport
()
{
'
use strict
'
;
var
id
=
0
;
var
outputs
=
{};
var
started
=
{};
var
websocket
=
new
WebSocket
(
'
ws://
'
+
window
.
location
.
host
+
'
/socket
'
);
websocket
.
onclose
=
function
()
{
console
.
log
(
'
websocket connection closed
'
);
}
var
pushedEmpty
=
(
window
.
location
.
pathname
==
"
/
"
);
function
inputChanged
()
{
if
(
pushedEmpty
)
{
websocket
.
onmessage
=
function
(
e
)
{
var
m
=
JSON
.
parse
(
e
.
data
);
var
output
=
outputs
[
m
.
Id
];
if
(
output
===
null
)
return
;
if
(
!
started
[
m
.
Id
])
{
output
({
Kind
:
'
start
'
});
started
[
m
.
Id
]
=
true
;
}
pushedEmpty
=
true
;
output
({
Kind
:
m
.
Kind
,
Body
:
m
.
Body
});
}
$
(
opts
[
'
shareURLEl
'
]).
hide
();
w
indow
.
history
.
pushState
(
null
,
""
,
"
/
"
);
function
send
(
m
)
{
w
ebsocket
.
send
(
JSON
.
stringify
(
m
)
);
}
function
popState
(
e
)
{
if
(
e
==
null
)
{
return
;
return
{
Run
:
function
(
body
,
output
,
options
)
{
var
thisID
=
id
+
''
;
id
++
;
outputs
[
thisID
]
=
output
;
send
({
Id
:
thisID
,
Kind
:
'
run
'
,
Body
:
body
,
Options
:
options
});
return
{
Kill
:
function
()
{
send
({
Id
:
thisID
,
Kind
:
'
kill
'
});
}
};
}
};
}
function
PlaygroundOutput
(
el
)
{
'
use strict
'
;
if
(
e
&&
e
.
state
&&
e
.
state
.
code
)
{
setBody
(
e
.
state
.
code
);
return
function
(
write
)
{
if
(
write
.
Kind
==
'
start
'
)
{
el
.
innerHTML
=
''
;
return
;
}
}
var
rewriteHistory
=
false
;
var
cl
=
'
system
'
;
if
(
write
.
Kind
==
'
stdout
'
||
write
.
Kind
==
'
stderr
'
)
cl
=
write
.
Kind
;
if
(
window
.
history
&&
window
.
history
.
pushState
&&
window
.
addEventListener
&&
opts
[
'
enableHistory
'
])
{
rewriteHistory
=
true
;
code
[
0
].
addEventListener
(
'
input
'
,
inputChanged
);
window
.
addEventListener
(
'
popstate
'
,
popState
)
}
var
m
=
write
.
Body
;
if
(
write
.
Kind
==
'
end
'
)
m
=
'
\n
Program exited
'
+
(
m
?(
'
:
'
+
m
):
'
.
'
);
var
seq
=
0
;
function
run
()
{
loading
();
seq
++
;
var
cur
=
seq
;
var
data
=
{
"
version
"
:
2
,
"
body
"
:
body
()
};
$
.
ajax
(
"
/compile
"
,
{
data
:
data
,
type
:
"
POST
"
,
dataType
:
"
json
"
,
success
:
function
(
data
)
{
if
(
seq
!=
cur
)
{
return
;
}
if
(
!
data
)
{
return
;
}
if
(
data
.
Errors
)
{
setOutput
(
null
,
data
.
Errors
);
return
;
}
setOutput
(
data
.
Events
,
false
);
},
error
:
function
()
{
output
.
addClass
(
"
error
"
).
text
(
"
Error communicating with remote server.
"
);
}
});
}
$
(
opts
[
'
runEl
'
]).
click
(
run
);
$
(
opts
[
'
fmtEl
'
]).
click
(
function
()
{
loading
();
$
.
ajax
(
"
/fmt
"
,
{
data
:
{
"
body
"
:
body
()},
type
:
"
POST
"
,
dataType
:
"
json
"
,
success
:
function
(
data
)
{
if
(
data
.
Error
)
{
setOutput
(
null
,
data
.
Error
);
return
;
}
setBody
(
data
.
Body
);
setOutput
(
null
);
}
});
});
if
(
m
.
indexOf
(
'
IMAGE:
'
)
===
0
)
{
// TODO(adg): buffer all writes before creating image
var
url
=
'
data:image/png;base64,
'
+
m
.
substr
(
6
);
var
img
=
document
.
createElement
(
'
img
'
);
img
.
src
=
url
;
el
.
appendChild
(
img
);
return
;
}
if
(
opts
[
'
shareEl
'
]
!=
null
&&
(
opts
[
'
shareURLEl
'
]
!=
null
||
opts
[
'
shareRedirect
'
]
!=
null
))
{
var
shareURL
;
if
(
opts
[
'
shareURLEl
'
])
{
shareURL
=
$
(
opts
[
'
shareURLEl
'
]).
hide
();
// ^L clears the screen.
var
s
=
m
.
split
(
'
\
x0c
'
);
if
(
s
.
length
>
1
)
{
el
.
innerHTML
=
''
;
m
=
s
.
pop
();
}
var
sharing
=
false
;
$
(
opts
[
'
shareEl
'
]).
click
(
function
()
{
if
(
sharing
)
return
;
sharing
=
true
;
var
sharingData
=
body
();
$
.
ajax
(
"
/share
"
,
{
processData
:
false
,
data
:
sharingData
,
type
:
"
POST
"
,
complete
:
function
(
xhr
)
{
sharing
=
false
;
if
(
xhr
.
status
!=
200
)
{
alert
(
"
Server error; try again.
"
);
return
;
}
if
(
opts
[
'
shareRedirect
'
])
{
window
.
location
=
opts
[
'
shareRedirect
'
]
+
xhr
.
responseText
;
}
if
(
shareURL
)
{
var
path
=
"
/p/
"
+
xhr
.
responseText
var
url
=
origin
(
window
.
location
)
+
path
;
shareURL
.
show
().
val
(
url
).
focus
().
select
();
if
(
rewriteHistory
)
{
var
historyData
=
{
"
code
"
:
sharingData
,
};
window
.
history
.
pushState
(
historyData
,
""
,
path
);
pushedEmpty
=
false
;
}
}
}
});
});
}
if
(
opts
[
'
toysEl
'
]
!=
null
)
{
$
(
opts
[
'
toysEl
'
]).
bind
(
'
change
'
,
function
()
{
var
toy
=
$
(
this
).
val
();
$
.
ajax
(
"
/doc/play/
"
+
toy
,
{
processData
:
false
,
type
:
"
GET
"
,
complete
:
function
(
xhr
)
{
if
(
xhr
.
status
!=
200
)
{
alert
(
"
Server error; try again.
"
)
return
;
}
setBody
(
xhr
.
responseText
);
}
});
});
m
=
m
.
replace
(
/&/g
,
'
&
'
);
m
=
m
.
replace
(
/</g
,
'
<
'
);
m
=
m
.
replace
(
/>/g
,
'
>
'
);
var
needScroll
=
(
el
.
scrollTop
+
el
.
offsetHeight
)
==
el
.
scrollHeight
;
var
span
=
document
.
createElement
(
'
span
'
);
span
.
className
=
cl
;
span
.
innerHTML
=
m
;
el
.
appendChild
(
span
);
if
(
needScroll
)
el
.
scrollTop
=
el
.
scrollHeight
-
el
.
offsetHeight
;
}
}
(
function
()
{
function
lineHighlight
(
error
)
{
var
regex
=
/prog.go:
([
0-9
]
+
)
/g
;
var
r
=
regex
.
exec
(
error
);
while
(
r
)
{
$
(
"
.lines div
"
).
eq
(
r
[
1
]
-
1
).
addClass
(
"
lineerror
"
);
r
=
regex
.
exec
(
error
);
}
}
function
highlightOutput
(
wrappedOutput
)
{
return
function
(
write
)
{
if
(
write
.
Body
)
lineHighlight
(
write
.
Body
);
wrappedOutput
(
write
);
}
}
function
lineClear
()
{
$
(
"
.lineerror
"
).
removeClass
(
"
lineerror
"
);
}
// opts is an object with these keys
// codeEl - code editor element
// outputEl - program output element
// runEl - run button element
// fmtEl - fmt button element (optional)
// shareEl - share button element (optional)
// shareURLEl - share URL text input element (optional)
// shareRedirect - base URL to redirect to on share (optional)
// toysEl - toys select element (optional)
// enableHistory - enable using HTML5 history API (optional)
// transport - playground transport to use (default is HTTPTransport)
function
playground
(
opts
)
{
var
code
=
$
(
opts
.
codeEl
);
var
transport
=
opts
[
'
transport
'
]
||
new
HTTPTransport
();
var
running
;
// autoindent helpers.
function
insertTabs
(
n
)
{
// find the selection start and end
var
start
=
code
[
0
].
selectionStart
;
var
end
=
code
[
0
].
selectionEnd
;
// split the textarea content into two, and insert n tabs
var
v
=
code
[
0
].
value
;
var
u
=
v
.
substr
(
0
,
start
);
for
(
var
i
=
0
;
i
<
n
;
i
++
)
{
u
+=
"
\t
"
;
}
u
+=
v
.
substr
(
end
);
// set revised content
code
[
0
].
value
=
u
;
// reset caret position after inserted tabs
code
[
0
].
selectionStart
=
start
+
n
;
code
[
0
].
selectionEnd
=
start
+
n
;
}
function
autoindent
(
el
)
{
var
curpos
=
el
.
selectionStart
;
var
tabs
=
0
;
while
(
curpos
>
0
)
{
curpos
--
;
if
(
el
.
value
[
curpos
]
==
"
\t
"
)
{
tabs
++
;
}
else
if
(
tabs
>
0
||
el
.
value
[
curpos
]
==
"
\n
"
)
{
break
;
}
}
setTimeout
(
function
()
{
insertTabs
(
tabs
);
},
1
);
}
function
keyHandler
(
e
)
{
if
(
e
.
keyCode
==
9
)
{
// tab
insertTabs
(
1
);
e
.
preventDefault
();
return
false
;
}
if
(
e
.
keyCode
==
13
)
{
// enter
if
(
e
.
shiftKey
)
{
// +shift
run
();
e
.
preventDefault
();
return
false
;
}
else
{
autoindent
(
e
.
target
);
}
}
return
true
;
}
code
.
unbind
(
'
keydown
'
).
bind
(
'
keydown
'
,
keyHandler
);
var
outdiv
=
$
(
opts
.
outputEl
).
empty
();
var
output
=
$
(
'
<pre/>
'
).
appendTo
(
outdiv
);
function
body
()
{
return
$
(
opts
.
codeEl
).
val
();
}
function
setBody
(
text
)
{
$
(
opts
.
codeEl
).
val
(
text
);
}
function
origin
(
href
)
{
return
(
""
+
href
).
split
(
"
/
"
).
slice
(
0
,
3
).
join
(
"
/
"
);
}
var
pushedEmpty
=
(
window
.
location
.
pathname
==
"
/
"
);
function
inputChanged
()
{
if
(
pushedEmpty
)
{
return
;
}
pushedEmpty
=
true
;
$
(
opts
.
shareURLEl
).
hide
();
window
.
history
.
pushState
(
null
,
""
,
"
/
"
);
}
function
popState
(
e
)
{
if
(
e
===
null
)
{
return
;
}
if
(
e
&&
e
.
state
&&
e
.
state
.
code
)
{
setBody
(
e
.
state
.
code
);
}
}
var
rewriteHistory
=
false
;
if
(
window
.
history
&&
window
.
history
.
pushState
&&
window
.
addEventListener
&&
opts
.
enableHistory
)
{
rewriteHistory
=
true
;
code
[
0
].
addEventListener
(
'
input
'
,
inputChanged
);
window
.
addEventListener
(
'
popstate
'
,
popState
);
}
function
setError
(
error
)
{
if
(
running
)
running
.
Kill
();
lineClear
();
lineHighlight
(
error
);
output
.
empty
().
addClass
(
"
error
"
).
text
(
error
);
}
function
loading
()
{
lineClear
();
if
(
running
)
running
.
Kill
();
output
.
removeClass
(
"
error
"
).
text
(
'
Waiting for remote server...
'
);
}
function
run
()
{
loading
();
running
=
transport
.
Run
(
body
(),
highlightOutput
(
PlaygroundOutput
(
output
[
0
])));
}
function
fmt
()
{
loading
();
$
.
ajax
(
"
/fmt
"
,
{
data
:
{
"
body
"
:
body
()},
type
:
"
POST
"
,
dataType
:
"
json
"
,
success
:
function
(
data
)
{
if
(
data
.
Error
)
{
setError
(
data
.
Error
);
}
else
{
setBody
(
data
.
Body
);
setError
(
""
);
}
}
});
}
$
(
opts
.
runEl
).
click
(
run
);
$
(
opts
.
fmtEl
).
click
(
fmt
);
if
(
opts
.
shareEl
!==
null
&&
(
opts
.
shareURLEl
!==
null
||
opts
.
shareRedirect
!==
null
))
{
var
shareURL
;
if
(
opts
.
shareURLEl
)
{
shareURL
=
$
(
opts
.
shareURLEl
).
hide
();
}
var
sharing
=
false
;
$
(
opts
.
shareEl
).
click
(
function
()
{
if
(
sharing
)
return
;
sharing
=
true
;
var
sharingData
=
body
();
$
.
ajax
(
"
/share
"
,
{
processData
:
false
,
data
:
sharingData
,
type
:
"
POST
"
,
complete
:
function
(
xhr
)
{
sharing
=
false
;
if
(
xhr
.
status
!=
200
)
{
alert
(
"
Server error; try again.
"
);
return
;
}
if
(
opts
.
shareRedirect
)
{
window
.
location
=
opts
.
shareRedirect
+
xhr
.
responseText
;
}
if
(
shareURL
)
{
var
path
=
"
/p/
"
+
xhr
.
responseText
;
var
url
=
origin
(
window
.
location
)
+
path
;
shareURL
.
show
().
val
(
url
).
focus
().
select
();
if
(
rewriteHistory
)
{
var
historyData
=
{
"
code
"
:
sharingData
};
window
.
history
.
pushState
(
historyData
,
""
,
path
);
pushedEmpty
=
false
;
}
}
}
});
});
}
if
(
opts
.
toysEl
!==
null
)
{
$
(
opts
.
toysEl
).
bind
(
'
change
'
,
function
()
{
var
toy
=
$
(
this
).
val
();
$
.
ajax
(
"
/doc/play/
"
+
toy
,
{
processData
:
false
,
type
:
"
GET
"
,
complete
:
function
(
xhr
)
{
if
(
xhr
.
status
!=
200
)
{
alert
(
"
Server error; try again.
"
);
return
;
}
setBody
(
xhr
.
responseText
);
}
});
});
}
}
window
.
playground
=
playground
;
})();
doc/style.css
View file @
1856286f
...
...
@@ -497,7 +497,10 @@ div.play .buttons a {
padding
:
10px
;
cursor
:
pointer
;
}
div
.play
.output
.exit
{
.output
.stderr
{
color
:
#933
;
}
.output
.system
{
color
:
#999
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment