forked from estelle/jsintro
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
3,518 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
;(function (global) { | ||
|
||
if ("EventSource" in window) return; | ||
|
||
var reTrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g; | ||
|
||
var EventSource = function (url) { | ||
var eventsource = this, | ||
interval = 500, // polling interval | ||
lastEventId = null, | ||
cache = ''; | ||
|
||
if (!url || typeof url != 'string') { | ||
throw new SyntaxError('Not enough arguments'); | ||
} | ||
|
||
this.URL = url; | ||
this.readyState = this.CONNECTING; | ||
this._pollTimer = null; | ||
this._xhr = null; | ||
|
||
function pollAgain() { | ||
eventsource._pollTimer = setTimeout(function () { | ||
poll.call(eventsource); | ||
}, interval); | ||
} | ||
|
||
function poll() { | ||
try { // force hiding of the error message... insane? | ||
if (eventsource.readyState == eventsource.CLOSED) return; | ||
|
||
var xhr = new XMLHttpRequest(); | ||
xhr.open('GET', eventsource.URL, true); | ||
xhr.setRequestHeader('Accept', 'text/event-stream'); | ||
xhr.setRequestHeader('Cache-Control', 'no-cache'); | ||
|
||
// we must make use of this on the server side if we're working with Android - because they don't trigger | ||
// readychange until the server connection is closed | ||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); | ||
|
||
if (lastEventId != null) xhr.setRequestHeader('Last-Event-ID', lastEventId); | ||
cache = ''; | ||
|
||
xhr.timeout = 50000; | ||
xhr.onreadystatechange = function () { | ||
if ((this.readyState == 3 || this.readyState == 4) && this.status == 200) { | ||
// on success | ||
if (eventsource.readyState == eventsource.CONNECTING) { | ||
eventsource.readyState = eventsource.OPEN; | ||
eventsource.dispatchEvent('open', { type: 'open' }); | ||
} | ||
|
||
// process this.responseText | ||
var parts = this.responseText.substr(cache.length).split("\n"), | ||
data = [], | ||
i = 0, | ||
line = ''; | ||
|
||
cache = this.responseText; | ||
|
||
// TODO handle 'event' (for buffer name), retry | ||
for (; i < parts.length; i++) { | ||
line = parts[i].replace(reTrim, ''); | ||
if (line.indexOf('data') == 0) { | ||
data.push(line.replace(/data:?\s*/, '')); | ||
} else if (line.indexOf('id:') == 0) { | ||
lastEventId = line.replace(/id:?\s*/, ''); | ||
} else if (line.indexOf('id') == 0) { // this resets the id | ||
lastEventId = null; | ||
} else if (line == '') { | ||
if (data.length) { | ||
var event = new MessageEvent(data.join('\n'), eventsource.url, lastEventId); | ||
eventsource.dispatchEvent('message', event); | ||
data = []; | ||
} | ||
} | ||
} | ||
|
||
if (this.readyState == 4) pollAgain(); | ||
// don't need to poll again, because we're long-loading | ||
} else if (eventsource.readyState !== eventsource.CLOSED) { | ||
if (this.readyState == 4) { // and some other status | ||
// dispatch error | ||
eventsource.readyState = eventsource.CONNECTING; | ||
eventsource.dispatchEvent('error', { type: 'error' }); | ||
pollAgain(); | ||
} else if (this.readyState == 0) { // likely aborted | ||
pollAgain(); | ||
} | ||
} | ||
}; | ||
|
||
xhr.send(); | ||
|
||
setTimeout(function () { | ||
if (true || xhr.readyState == 3) xhr.abort(); | ||
}, xhr.timeout); | ||
|
||
eventsource._xhr = xhr; | ||
|
||
} catch (e) { // in an attempt to silence the errors | ||
eventsource.dispatchEvent('error', { type: 'error', data: e.message }); // ??? | ||
} | ||
}; | ||
|
||
poll(); // init now | ||
}; | ||
|
||
EventSource.prototype = { | ||
close: function () { | ||
// closes the connection - disabling the polling | ||
this.readyState = this.CLOSED; | ||
clearInterval(this._pollTimer); | ||
this._xhr.abort(); | ||
}, | ||
CONNECTING: 0, | ||
OPEN: 1, | ||
CLOSED: 2, | ||
dispatchEvent: function (type, event) { | ||
var handlers = this['_' + type + 'Handlers']; | ||
if (handlers) { | ||
for (var i = 0; i < handlers.length; i++) { | ||
handlers.call(this, event); | ||
} | ||
} | ||
|
||
if (this['on' + type]) { | ||
this['on' + type].call(this, event); | ||
} | ||
}, | ||
addEventListener: function (type, handler) { | ||
if (!this['_' + type + 'Handlers']) { | ||
this['_' + type + 'Handlers'] = []; | ||
} | ||
|
||
this['_' + type + 'Handlers'].push(handler); | ||
}, | ||
removeEventListener: function () { | ||
// TODO | ||
}, | ||
onerror: null, | ||
onmessage: null, | ||
onopen: null, | ||
readyState: 0, | ||
URL: '' | ||
}; | ||
|
||
var MessageEvent = function (data, origin, lastEventId) { | ||
this.data = data; | ||
this.origin = origin; | ||
this.lastEventId = lastEventId || ''; | ||
}; | ||
|
||
MessageEvent.prototype = { | ||
data: null, | ||
type: 'message', | ||
lastEventId: '', | ||
origin: '' | ||
}; | ||
|
||
if ('module' in global) module.exports = EventSource; | ||
global.EventSource = EventSource; | ||
|
||
})(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
var ccCache = {}; | ||
var ccPosition = false; | ||
|
||
function getProps(cmd) { | ||
var surpress = {}; | ||
|
||
if (!ccCache[cmd]) { | ||
try { | ||
// surpress alert boxes because they'll actually do something when we're looking | ||
// up properties inside of the command we're running | ||
surpress.alert = sandboxframe.contentWindow.alert; | ||
sandboxframe.contentWindow.alert = function () {}; | ||
|
||
// loop through all of the properties available on the command (that's evaled) | ||
ccCache[cmd] = sandboxframe.contentWindow.eval('console.props(' + cmd + ')').sort(); | ||
|
||
// return alert back to it's former self | ||
sandboxframe.contentWindow.alert = surpress.alert; | ||
} catch (e) { | ||
ccCache[cmd] = []; | ||
} | ||
|
||
// if the return value is undefined, then it means there's no props, so we'll | ||
// empty the code completion | ||
if (ccCache[cmd][0] == 'undefined') ccOptions[cmd] = []; | ||
ccPosition = 0; | ||
} | ||
|
||
return ccCache[cmd]; | ||
} | ||
|
||
function codeComplete(event) { | ||
var cmd = cursor.textContent.split(/[;\s]+/g).pop(), | ||
which = whichKey(event), | ||
cc, | ||
props = []; | ||
|
||
if (cmd) { | ||
if (cmd.substr(-1) == '.') { | ||
// get the command without the '.' so we can eval it and lookup the properties | ||
cmd = cmd.substr(0, cmd.length - 1); | ||
|
||
props = getProps(cmd); | ||
} else { | ||
props = getProps(cmd); | ||
} | ||
|
||
if (props.length) { | ||
if (which == 9) { // tabbing cycles through the code completion | ||
if (event.shiftKey) { | ||
// backwards | ||
ccPosition = ccPosition == 0 ? props.length - 1 : ccPosition-1; | ||
} else { | ||
ccPosition = ccPosition == props.length - 1 ? 0 : ccPosition+1; | ||
} | ||
|
||
} else { | ||
ccPosition = 0; | ||
} | ||
|
||
// position the code completion next to the cursor | ||
if (!cursor.nextSibling) { | ||
cc = document.createElement('span'); | ||
cc.className = 'suggest'; | ||
exec.appendChild(cc); | ||
} | ||
|
||
cursor.nextSibling.innerHTML = props[ccPosition]; | ||
exec.value = exec.textContent; | ||
|
||
if (which == 9) return false; | ||
} | ||
} else { | ||
ccPosition = false; | ||
} | ||
|
||
if (ccPosition === false && cursor.nextSibling) { | ||
exec.removeChild(cursor.nextSibling); | ||
} | ||
|
||
exec.value = exec.textContent; | ||
} |
Oops, something went wrong.