Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Marco Kellershoff
pwny.gorilla.moe
Commits
7d2e089c
Verified
Commit
7d2e089c
authored
Dec 07, 2017
by
Marco Kellershoff
🤸
Browse files
Hide output "window" on load
Show only when "Run"-button is pressed and "isCompilable" === true
parent
1ed9a6bc
Changes
1
Hide whitespace changes
Inline
Side-by-side
assets/pwny.js
View file @
7d2e089c
/*jshint esversion: 6 */
(
function
(
window
,
document
){
"
use strict
"
;
var
Pwny
=
function
()
{
var
self
=
this
,
googleapikeys
=
{},
getWidth
=
function
(){
return
window
.
innerWidth
;},
window_min_width
=
1000
,
LOCAL_STORAGE_TEMPLATE_NAME
=
'
codetest_templates
'
,
SYNTAXES
=
[
'
html
'
,
'
javascript
'
,
'
sh
'
,
'
php
'
,
'
mysql
'
,
'
css
'
,
'
coffee
'
,
'
json
'
,
'
markdown
'
,
'
xml
'
,
'
sass
'
,
'
less
'
],
EDITOR
=
null
,
compression
=
{},
my_lzma
=
new
window
.
LZMA
(
'
assets/lzma_worker.js
'
);
this
.
version
=
3
;
this
.
getGoogleApiKey
=
function
(
k
)
{
return
googleapikeys
[
k
];
};
this
.
getGoogleApiKeys
=
function
()
{
return
googleapikeys
;
};
this
.
setGoogleApiKeys
=
function
(
apikeys
)
{
googleapikeys
=
apikeys
;
};
this
.
append
=
function
(
element
,
target
)
{
target
=
target
||
document
.
body
;
if
(
typeof
target
===
'
string
'
)
target
=
document
.
querySelector
(
target
);
var
elementCallback
=
function
(
el
)
{
target
.
appendChild
(
el
);
};
if
(
element
.
length
)
{
element
.
forEach
(
elementCallback
);
}
else
{
target
.
appendChild
(
element
);
}
};
this
.
createElement
=
function
(
node_name
,
node_contents
,
node_attributes
)
{
var
el
=
document
.
createElement
(
node_name
);
var
typeof_contents
=
(
typeof
node_contents
);
var
attributesCallback
=
function
(
attr
)
{
el
.
setAttribute
(
attr
[
0
],
attr
[
1
]);
};
if
(
node_attributes
&&
node_attributes
.
length
)
{
node_attributes
.
forEach
(
attributesCallback
);
}
var
contentsCallback
=
function
(
content
)
{
el
.
appendChild
(
content
);
};
switch
(
typeof_contents
)
{
case
'
string
'
:
el
.
innerHTML
=
node_contents
;
break
;
case
'
object
'
:
if
(
node_contents
)
{
if
(
node_contents
.
length
)
{
node_contents
.
forEach
(
contentsCallback
);
}
else
{
el
.
appendChild
(
node_contents
);
}
}
break
;
default
:
break
;
}
return
el
;
};
this
.
setupHtml
=
function
()
{
self
.
append
(
self
.
createElement
(
'
img
'
,
null
,
[
[
'
id
'
,
'
logo
'
],
[
'
src
'
,
'
pwny.png
'
]
]
),
'
#app
'
);
self
.
append
(
self
.
createElement
(
'
ul
'
),
'
#drawer
'
);
self
.
append
(
self
.
createElement
(
'
input
'
,
null
,
[[
'
id
'
,
'
file
'
],
[
'
name
'
,
'
file
'
],
[
'
type
'
,
'
file
'
]]));
self
.
append
(
[
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
button
'
,
'
Run
'
,
[[
'
id
'
,
'
btn_run
'
]])]),
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
select
'
,
null
,
[[
'
id
'
,
'
syntax
'
]])]),
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
button
'
,
'
Open File
'
,
[[
'
id
'
,
'
btn_file
'
]])]),
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
button
'
,
'
Add Template
'
,
[[
'
id
'
,
'
btn_add
'
]])]),
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
select
'
,
null
,
[[
'
id
'
,
'
templates
'
]])]),
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
button
'
,
'
Delete Template
'
,
[[
'
id
'
,
'
btn_delete
'
]])]),
self
.
createElement
(
'
li
'
,
[
self
.
createElement
(
'
button
'
,
'
Share
'
,
[[
'
id
'
,
'
btn_share
'
]])])
],
'
#drawer ul
'
);
self
.
append
(
self
.
createElement
(
'
div
'
,
null
,
[
[
'
id
'
,
'
table
'
],
[
'
class
'
,
'
container
'
]
]
),
'
#app
'
);
self
.
append
(
self
.
createElement
(
'
div
'
,
null
,
[
[
'
id
'
,
'
table-row
'
],
[
'
class
'
,
'
row
'
]
]
),
'
#table
'
);
self
.
append
(
[
self
.
createElement
(
'
div
'
,
null
,
[
[
'
id
'
,
'
col1
'
],
[
'
class
'
,
'
col-xs-6
'
]
]
),
self
.
createElement
(
'
div
'
,
null
,
[
[
'
id
'
,
'
col2
'
],
[
'
class
'
,
'
col-xs-6
'
]
]
)
],
'
#table-row
'
);
self
.
append
(
self
.
createElement
(
'
textarea
'
,
null
,
[
[
'
id
'
,
'
textarea
'
]
]
),
'
#col1
'
);
self
.
append
(
[
self
.
createElement
(
'
iframe
'
,
null
,
[
[
'
id
'
,
'
output
'
]
]
)
],
'
#col2
'
);
};
this
.
compression
=
{
convertToFormatedHex
:
function
(
byte_arr
)
{
var
hex_str
=
""
,
i
,
len
,
tmp_hex
;
if
(
!
self
.
isArray
(
byte_arr
))
{
return
false
;
}
len
=
byte_arr
.
length
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
i
!==
0
)
tmp_hex
+=
'
'
;
if
(
byte_arr
[
i
]
<
0
)
{
byte_arr
[
i
]
=
byte_arr
[
i
]
+
256
;
}
tmp_hex
=
byte_arr
[
i
].
toString
(
16
);
// Add leading zero.
if
(
tmp_hex
.
length
===
1
)
{
tmp_hex
=
'
0
'
+
tmp_hex
;
}
hex_str
+=
tmp_hex
;
}
return
hex_str
;
},
compress
:
function
(
data
,
cb
)
{
my_lzma
.
compress
(
data
,
9
,
function
(
result
)
{
cb
(
false
,
self
.
compression
.
convertToFormatedHex
(
result
));
});
},
decompress
:
function
(
data
,
cb
)
{
var
byte_arr
=
self
.
compression
.
convertFormatedHexToBytes
(
data
),
error
=
false
;
my_lzma
.
decompress
(
byte_arr
,
function
(
result
)
{
if
(
result
===
false
)
cb
(
true
,
[]);
else
cb
(
false
,
result
);
});
},
convertFormatedHexToBytes
:
function
(
hex_str
)
{
var
count
=
0
,
hex_arr
,
hex_data
=
[],
hex_len
,
i
;
if
(
hex_str
.
trim
()
===
""
)
{
return
[];
}
// Check for invalid hex characters.
if
(
/
[^
0-9a-fA-F
]
/
.
test
(
hex_str
))
{
return
false
;
}
hex_arr
=
hex_str
.
match
(
/.
{2}
/g
);
hex_len
=
hex_arr
.
length
;
for
(
i
=
0
;
i
<
hex_len
;
i
++
)
{
if
(
hex_arr
[
i
].
trim
()
===
""
)
{
continue
;
}
hex_data
[
count
++
]
=
parseInt
(
hex_arr
[
i
],
16
);
}
return
hex_data
;
},
prepareData
:
function
(
str
)
{
var
arr
;
// If the string is a JSON array, use that. This allows us to compress a byte array.
if
(
str
[
0
]
===
"
[
"
&&
str
.
slice
(
-
1
)
===
"
]
"
)
{
try
{
arr
=
JSON
.
parse
(
str
);
}
catch
(
e
)
{}
}
if
(
arr
)
{
return
arr
;
}
return
str
;
}
};
this
.
getEditorSyntax
=
function
()
{
var
mode_id
=
EDITOR
.
getSession
().
$modeId
;
var
syntax
=
mode_id
.
split
(
'
/
'
)[
2
];
return
syntax
;
};
this
.
setEditorSyntax
=
function
(
syntax
)
{
if
(
this
.
isAllowedSyntax
(
syntax
)
===
true
)
{
EDITOR
.
getSession
().
setMode
(
'
ace/mode/
'
+
syntax
);
var
synsel_children
=
document
.
querySelectorAll
(
'
#syntax option
'
);
var
cb
=
function
(
el
)
{
if
(
el
.
innerHTML
===
syntax
)
{
el
.
selected
=
true
;
return
true
;
}
};
synsel_children
.
forEach
(
cb
);
this
.
showAndHideRun
();
}
};
this
.
addDomReadyEvent
=
function
(
cb
)
{
if
(
document
.
readyState
===
'
complete
'
)
{
return
window
.
setTimeout
(
cb
,
1
);
}
else
{
document
.
addEventListener
(
'
DOMContentLoaded
'
,
function
()
{
cb
();
});
}
};
this
.
isAllowedSyntax
=
function
(
syntax
)
{
return
SYNTAXES
.
includes
(
syntax
);
};
this
.
autoRun
=
function
()
{
window
.
mockhtml
();
var
app
=
document
.
querySelector
(
'
#app
'
);
var
logo
=
document
.
querySelector
(
'
#logo
'
);
var
drawertoggle
=
document
.
querySelector
(
'
#drawer-toggle
'
);
var
drawerlabel
=
document
.
querySelector
(
'
#drawer-toggle-label
'
);
var
drawer
=
document
.
querySelector
(
'
#drawer
'
);
var
ifr
=
document
.
querySelector
(
'
#output
'
);
logo
.
parentNode
.
removeChild
(
logo
);
drawer
.
parentNode
.
removeChild
(
drawer
);
drawerlabel
.
parentNode
.
removeChild
(
drawerlabel
);
drawertoggle
.
parentNode
.
removeChild
(
drawertoggle
);
app
.
style
.
margin
=
'
0
'
;
app
.
style
.
padding
=
'
0
'
;
col2
.
style
.
display
=
'
block
'
;
col2
.
style
.
width
=
'
100%
'
;
col1
.
parentNode
.
removeChild
(
col1
);
$
(
ifr
).
addClass
(
'
fullscreen
'
);
$
(
col2
).
removeClass
(
'
col-xs-6
'
);
$
(
'
#table
'
).
addClass
(
'
fullscreen
'
);
};
this
.
loadFromHash
=
function
()
{
var
hash
=
window
.
location
.
hash
,
loc
=
hash
.
indexOf
(
'
#!/
'
),
virtual_url
=
''
,
url_params
=
null
,
syntax
=
'
html
'
,
shared_code
=
''
;
if
(
loc
===
0
&&
hash
.
length
>
3
)
{
virtual_url
=
hash
.
substring
(
3
);
url_params
=
self
.
getUrlParams
(
virtual_url
);
try
{
shared_code
=
url_params
.
get
(
'
t
'
);
syntax
=
url_params
.
get
(
'
s
'
);
if
(
self
.
isAllowedSyntax
(
syntax
)
===
true
)
{
self
.
setEditorSyntax
(
syntax
);
}
self
.
compression
.
decompress
(
shared_code
,
function
(
err
,
result
){
if
(
!
err
)
{
EDITOR
.
setValue
(
result
);
EDITOR
.
resize
(
true
);
var
line
=
url_params
.
get
(
'
l
'
);
if
(
line
)
{
var
column
=
url_params
.
get
(
'
c
'
)
||
0
;
EDITOR
.
scrollToLine
(
line
,
true
,
true
,
function
()
{});
EDITOR
.
gotoLine
(
line
,
column
,
true
);
EDITOR
.
focus
();
}
if
(
url_params
.
get
(
'
a
'
)
===
'
1
'
)
{
self
.
hideLoading
();
self
.
autoRun
();
return
;
}
}
else
{
window
.
alert
(
'
No valid token received
'
);
}
self
.
hideLoading
();
});
}
catch
(
ex
)
{
console
.
log
(
ex
);
window
.
alert
(
'
No valid token received
'
);
self
.
hideLoading
();
}
}
else
{
self
.
hideLoading
();
}
};
this
.
showLoading
=
function
()
{
app
.
style
.
display
=
'
none
'
;
$
(
'
#loading
'
).
css
({
display
:
'
block
'
});
$
(
'
#drawer-toggle-label
'
).
css
({
display
:
'
none
'
});
};
this
.
hideLoading
=
function
()
{
$
(
"
#loading
"
).
fadeOut
(
"
slow
"
,
function
()
{
$
(
'
#drawer-toggle-label
'
).
fadeIn
(
"
slow
"
);
$
(
app
).
fadeIn
(
"
slow
"
);
});
};
this
.
deleteTemplate
=
function
()
{
var
templates
=
window
.
localStorage
.
getItem
(
LOCAL_STORAGE_TEMPLATE_NAME
)
||
'
{}
'
;
templates
=
JSON
.
parse
(
templates
);
var
tplsel
=
document
.
getElementById
(
'
templates
'
);
var
index
=
tplsel
.
selectedIndex
;
var
opt
=
tplsel
.
children
[
index
];
if
(
opt
.
value
&&
opt
.
value
.
length
&&
templates
[
opt
.
value
]
)
{
delete
templates
[
opt
.
value
];
window
.
localStorage
.
setItem
(
LOCAL_STORAGE_TEMPLATE_NAME
,
JSON
.
stringify
(
templates
));
self
.
fillTemplates
();
}
};
this
.
fillTemplates
=
function
()
{
var
templates
=
window
.
localStorage
.
getItem
(
LOCAL_STORAGE_TEMPLATE_NAME
)
||
'
{}
'
;
templates
=
JSON
.
parse
(
templates
);
var
tplsel
=
document
.
getElementById
(
'
templates
'
);
tplsel
.
innerHTML
=
'
<option value="">-- Templates --</option>
'
;
for
(
var
tpl_name
in
templates
)
{
var
opt
=
document
.
createElement
(
'
option
'
);
opt
.
innerHTML
=
tpl_name
;
opt
.
value
=
tpl_name
;
tplsel
.
appendChild
(
opt
);
}
};
this
.
isCompilable
=
function
()
{
var
comp
=
[
'
html
'
,
'
javascript
'
];
var
current_syntax
=
this
.
getEditorSyntax
();
return
comp
.
includes
(
current_syntax
);
};
this
.
showAndHideRun
=
function
()
{
var
is_compilable
=
self
.
isCompilable
();
if
(
is_compilable
===
false
)
{
$
(
col1
).
removeClass
(
'
col-xs-6
'
);
$
(
col1
).
addClass
(
'
col-xs-12
'
);
$
(
col2
).
addClass
(
'
hidden
'
);
btn_run
.
style
.
display
=
'
none
'
;
}
else
{
$
(
col1
).
addClass
(
'
col-xs-6
'
);
$
(
col1
).
removeClass
(
'
col-xs-12
'
);
$
(
col2
).
removeClass
(
'
hidden
'
);
btn_run
.
style
.
display
=
'
inline-block
'
;
}
};
this
.
fillSyntax
=
function
()
{
var
synsel
=
document
.
getElementById
(
'
syntax
'
);
var
current_syntax
=
self
.
getEditorSyntax
();
var
_filla
=
function
(
tpl_name
)
{
var
opt
=
document
.
createElement
(
'
option
'
);
if
(
current_syntax
===
tpl_name
)
{
opt
.
selected
=
true
;
}
opt
.
innerHTML
=
tpl_name
;
opt
.
value
=
tpl_name
;
synsel
.
appendChild
(
opt
);
};
SYNTAXES
.
forEach
(
_filla
);
self
.
showAndHideRun
();
};
this
.
getUrlParams
=
function
(
url
)
{
var
link
=
document
.
createElement
(
'
a
'
);
link
.
href
=
url
;
var
link_search
=
link
.
search
;
var
params
=
new
Map
();
var
arrCb
=
function
(
param
)
{
var
spl
=
param
.
split
(
'
=
'
);
params
.
set
(
spl
[
0
],
spl
[
1
]);
};
if
(
link_search
&&
link_search
.
length
)
{
link_search
=
link_search
.
substring
(
1
);
var
arr
=
link_search
.
split
(
'
&
'
);
arr
.
forEach
(
arrCb
);
}
return
params
;
};
this
.
isArray
=
function
(
input
)
{
return
input
&&
typeof
input
===
"
object
"
&&
(
input
instanceof
Array
||
(
input
.
buffer
&&
input
.
buffer
instanceof
ArrayBuffer
));
};
this
.
initGoogleApiKeys
=
function
(
cb
)
{
$
.
ajax
({
url
:
'
googleapikeys.json
'
,
method
:
"
GET
"
,
}).
done
(
function
(
data
){
self
.
setGoogleApiKeys
(
data
);
if
(
cb
)
{
cb
();
}
});
};
this
.
shortenUrl
=
function
(
longUrl
,
cb
)
{
var
apikey
=
self
.
getGoogleApiKey
(
'
urlshortener
'
);
if
(
!
apikey
)
{
self
.
initGoogleApiKeys
(
function
(){
self
.
shortenUrl
(
longUrl
,
cb
);
});
}
else
{
$
.
ajax
({
url
:
'
https://www.googleapis.com/urlshortener/v1/url?key=
'
+
apikey
,
method
:
"
POST
"
,
processData
:
false
,
dataType
:
"
json
"
,
contentType
:
"
application/json
"
,
data
:
JSON
.
stringify
({
"
longUrl
"
:
longUrl
})
}).
done
(
function
(
data
){
cb
(
data
);
});
}
};
this
.
showShareWindow
=
function
(
link
)
{
var
$shareDialogue
=
$
(
'
#shareDialogue
'
);
var
shareUrlBox
=
$shareDialogue
.
find
(
'
#shareUrlBox
'
);
shareUrlBox
.
val
(
link
);
$shareDialogue
.
modal
(
'
toggle
'
);
};
this
.
init
=
function
()
{
self
.
showLoading
();
new
Clipboard
(
'
#copyShareUrlButton
'
);
self
.
setupHtml
();
document
.
getElementById
(
'
templates
'
).
onchange
=
function
()
{
var
templates
=
window
.
localStorage
.
getItem
(
LOCAL_STORAGE_TEMPLATE_NAME
)
||
'
{}
'
;
templates
=
JSON
.
parse
(
templates
);
var
index
=
this
.
selectedIndex
;
var
opt
=
this
.
children
[
index
];
if
(
opt
.
value
&&
opt
.
value
.
length
&&
templates
[
opt
.
value
]
)
{
EDITOR
.
setValue
(
templates
[
opt
.
value
].
src
);
self
.
setEditorSyntax
(
templates
[
opt
.
value
].
syntax
);
}
};
self
.
fillTemplates
();
btn_run
.
onclick
=
function
(
evt
){
evt
.
preventDefault
();
window
.
mockhtml
();
};
btn_add
.
onclick
=
function
(
evt
){
evt
.
preventDefault
();
var
tpl_name
=
window
.
prompt
(
'
Save as template? Enter a name for the template
'
,
''
);
if
(
tpl_name
!==
null
&&
tpl_name
.
length
)
{
var
tpls
=
window
.
localStorage
.
getItem
(
LOCAL_STORAGE_TEMPLATE_NAME
)
||
'
{}
'
;
tpls
=
JSON
.
parse
(
tpls
);
tpls
[
tpl_name
]
=
{
src
:
EDITOR
.
getValue
(),
syntax
:
self
.
getEditorSyntax
()
};
window
.
localStorage
.
setItem
(
LOCAL_STORAGE_TEMPLATE_NAME
,
JSON
.
stringify
(
tpls
));
self
.
fillTemplates
();
}
};
btn_delete
.
onclick
=
function
(
evt
){
evt
.
preventDefault
();
self
.
deleteTemplate
();
};
var
getShareableLink
=
(
opts
,
cb
)
=>
{
opts
=
opts
||
{};
var
syntax
=
self
.
getEditorSyntax
();
var
cursorPosition
=
EDITOR
.
getCursorPosition
();
var
max_link_length
=
8000
;
var
port
=
(
window
.
location
.
port
===
""
)
?
80
:
parseInt
(
window
.
location
.
port
,
10
);
if
(
port
===
80
||
port
===
443
)
{
port
=
''
;
}
else
{
port
=
'
:
'
+
port
;
}
self
.
compression
.
compress
(
EDITOR
.
getValue
(),
function
(
err
,
result
){
var
link
=
window
.
location
.
protocol
+
'
//
'
+
window
.
location
.
hostname
+
port
+
'
/#!/?s=
'
+
syntax
+
'
&c=
'
+
cursorPosition
.
column
+
'
&l=
'
+
(
cursorPosition
.
row
+
1
)
+
'
&t=
'
+
result
.
toString
();
// http://stackoverflow.com/questions/15090220/maximum-length-for-url-in-chrome-browser
// var max_link_length = 2083;
// not giving a fuck about other browsers than chrome
if
(
link
.
length
>
max_link_length
)
{
cb
(
"
Too much code to share :( Try reducing your code and try again!
"
,
link
);
}
else
{
cb
(
false
,
link
);
}
});
};
var
getShareableLinkCallback
=
(
err
,
link
)
=>
{
if
(
err
===
false
)
{
self
.
showShareWindow
(
link
);
}
else
{
alert
(
err
);
}
};
btn_share
.
onclick
=
function
(
evt
)
{
evt
.
preventDefault
();
getShareableLink
({},
getShareableLinkCallback
);
};
window
.
mockhtml
=
function
(){
var
val
=
''
;
var
syntax
=
self
.
getEditorSyntax
();
if
(
syntax
===
'
html
'
)
{
val
=
EDITOR
.
getValue
();
}
else
if
(
syntax
===
'
javascript
'
)
{
val
=
'
<!DOCTYPE html><html><head><title></title></head>
'
+
'
<body style="background-color: black;"><script>
'
+
EDITOR
.
getValue
()
+
'
</script></body></html>
'
;
}
var
ifrm
=
document
.
getElementById
(
'
output
'
);
ifrm
.
style
.
backgroundColor
=
'
#fff
'
;
ifrm
=
ifrm
.
contentWindow
||
ifrm
.
contentDocument
||
ifrm
.
contentDocument
.
body
;
ifrm
.
document
.
open
();
try
{
ifrm
.
document
.
write
(
val
);
}
catch
(
ifrdocwrite_ex
)
{
console
.
log
(
ifrdocwrite_ex
);
}
ifrm
.
document
.
close
();
return
false
;
};
ace
.
require
(
"
ace/ext/language_tools
"
);
EDITOR
=
ace
.
edit
(
'
textarea
'
);
EDITOR
.
setTheme
(
'
ace/theme/tomorrow_night_eighties
'
);
EDITOR
.
getSession
().
setMode
(
'
ace/mode/html
'
);
EDITOR
.
$blockScrolling
=
Infinity
;