Skip to content

Instantly share code, notes, and snippets.

@kiy0taka
Created March 9, 2010 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kiy0taka/326626 to your computer and use it in GitHub Desktop.
Save kiy0taka/326626 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name GroovyWebConsole
// @namespace http://d.hatena.ne.jp/kiy0taka/
// @include http://gist.github.com/
// @include https://gist.github.com/
// @include http://gist.github.com/*/edit
// @include https://gist.github.com/*/edit
// ==/UserScript==
var LOADER_SRC = 'data:image/gif;base64,'+
'R0lGODlhKwALAPEAAP///wAAAIKCggAAACH+GkNyZWF0ZWQgd2l0aCBhamF4bG9hZC5pbmZvACH5'+
'BAAKAAAAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAAKwALAAACMoSOCMuW2diD88UKG95W88uF4DaG'+
'WFmhZid93pq+pwxnLUnXh8ou+sSz+T64oCAyTBUAACH5BAAKAAEALAAAAAArAAsAAAI9xI4IyyAP'+
'YWOxmoTHrHzzmGHe94xkmJifyqFKQ0pwLLgHa82xrekkDrIBZRQab1jyfY7KTtPimixiUsevAAAh'+
'+QQACgACACwAAAAAKwALAAACPYSOCMswD2FjqZpqW9xv4g8KE7d54XmMpNSgqLoOpgvC60xjNonn'+
'yc7p+VKamKw1zDCMR8rp8pksYlKorgAAIfkEAAoAAwAsAAAAACsACwAAAkCEjgjLltnYmJS6Bxt+'+
'sfq5ZUyoNJ9HHlEqdCfFrqn7DrE2m7Wdj/2y45FkQ13t5itKdshFExC8YCLOEBX6AhQAADsAAAAA'+
'AAAAAAA=';
function each(arr, func) {
for (var i=0,n=arr.length; i<n; i++) func(arr[i], i)
}
const isMacOS = !!navigator.userAgent.match(/Mac OS/)
function xpath(path, node) {
node = node || document
var s = document.evaluate(path, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)
var r = []
for (var i=0,n=s.snapshotLength; i<n; i++) {
r.push(s.snapshotItem(i))
}
return r;
}
GM_addStyle(<><![CDATA[
.groovywebconsole {
margin: 0px 10px 3px 10px;
}
.groovywebconsole .link {
color: #4183C4;
cursor: pointer;
font-weight: bold;
}
.groovywebconsole .link:hover {
text-decoration: underline;
}
.groovywebconsole pre {
display: none;
border: 1px solid silver;
padding: 3px;
min-height: 1.4em;
overflow-y: scroll;
}
.groovywebconsole .progress {
height: 18px;
display: none;
}
]]></>.toString())
function ResultPane(result, output, stacktrace, resultPane, outputPane, stacktracePane) {
this.result = result
this.output = output
this.stacktrace = stacktrace
this.resultPane = resultPane
this.outputPane = outputPane
this._addEvent('result', resultPane)
this._addEvent('output', outputPane)
this._addEvent('stacktrace', stacktracePane)
this.stacktracePane = stacktracePane
this.linkList = [result, output, stacktrace]
this.paneList = [resultPane, outputPane, stacktracePane]
}
ResultPane.prototype = {
_addEvent: function(name, pane) {
var self = this;
this[name].addEventListener('click', function() {
self.toggle(name)
}, false)
},
toggle: function(name) {
var targetPane = this[name+'Pane']
var targetLink = this[name]
each(this.paneList, function(pane) {
pane.style.display = (pane == targetPane) ? 'block' : 'none'
})
each(this.linkList, function(link) {
link.style.color = (link == targetLink) ? 'orange' : ''
})
},
update: function(data) {
this.resultPane.textContent = data.executionResult
this.outputPane.textContent = data.outputText
this.stacktracePane.textContent = data.stacktraceText
if (data.outputText) this.toggle('output')
if (data.executionResult && data.executionResult != 'null') this.toggle('result')
if (data.stacktraceText) this.toggle('stacktrace')
}
}
each(xpath('//div[@class="file"]'), function(file) {
var div = document.createElement('div')
div.className = 'groovywebconsole'
div.innerHTML = <>
<div>
<div class="menu">
<span class="link" name="execute">Run</span>
<span class="link" name="result">Result</span>
<span class="link" name="output">Output</span>
<span class="link" name="stacktrace">Stacktrace</span>
</div>
<div class="progress"><img src="@icon@" alt="Run" /></div>
<div>
<pre name="resultPane">-Result-</pre>
<pre name="outputPane">-Output-</pre>
<pre name="stacktracePane">-Stacktrace-</pre>
</div>
</div>
</>.toString().replace(/@icon@/, LOADER_SRC)
file.appendChild(div)
var t = xpath('.//div[@class="input"]/textarea[position()=last()]', file)[0]
var menu = xpath('.//div[@class="menu"]')[0]
var progress = xpath('.//div[@class="progress"]', file)[0]
var execute = function() {
menu.style.display = 'none'
progress.style.display = 'block'
GM_xmlhttpRequest({
method: 'POST',
url: 'http://groovyconsole.appspot.com/executor.groovy',
headers: {'Content-type': 'application/x-www-form-urlencoded'},
data: 'script=' + encodeURIComponent(t.value),
onload: function(res) {
try {
resultPane.update(eval('(' + res.responseText + ')'))
} catch (e) {
alert(e.message)
}
menu.style.display = ''
progress.style.display = 'none'
}
})
}
t.addEventListener('keydown', function(e) {
var ctrlKey = isMacOS ? e.metaKey : e.ctrlKey
if (ctrlKey && e.keyCode == 13) {
execute()
e.preventDefault()
}
else if (e.keyCode == 9) {
var start = t.selectionStart
var end = t.selectionEnd
if (start == end) {
t.value = t.value.substring(0, start) + ' ' + t.value.substring(start)
t.setSelectionRange(start+4, start+4)
} else {
var i=start
for (; i>0; i--) if (t.value[i] == '\n') break;
var orgLength = t.value.substring(i, end).length
if (e.shiftKey) {
var indentedValue = t.value.substring(i, end).replace(/^ /mg, '')
t.value = t.value.substring(0, i) + indentedValue + t.value.substring(end)
t.setSelectionRange(i, end + (orgLength - indentedValue.length))
} else {
var indentedValue = t.value.substring(i, end).replace(/^/mg, ' ')
t.value = t.value.substring(0, i) + indentedValue + t.value.substring(end)
t.setSelectionRange(i, end + (indentedValue.length - orgLength))
}
}
e.preventDefault()
}
}, false)
var resultPane = new ResultPane(
xpath('.//span[@name="result"]', file)[0],
xpath('.//span[@name="output"]', file)[0],
xpath('.//span[@name="stacktrace"]', file)[0],
xpath('.//pre[@name="resultPane"]', file)[0],
xpath('.//pre[@name="outputPane"]', file)[0],
xpath('.//pre[@name="stacktracePane"]', file)[0]
)
xpath('.//span[@name="execute"]', file)[0].addEventListener('click', execute, false)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment