urbit/web/lib/urb.js

311 lines
9.3 KiB
JavaScript
Raw Normal View History

window.urb = window.urb || {}
window.urb.appl = window.urb.appl || null
2015-03-20 01:21:14 +03:00
window.urb.req = function(method,url,params,json,cb) {
var xhr = new XMLHttpRequest()
2015-03-20 02:35:10 +03:00
method = method.toUpperCase()
if(method == "PUT" || method == "DELETE")
xhr.open("POST", url+"?"+method)
else xhr.open(method, url)
2015-03-20 01:21:14 +03:00
if(json)
xhr.setRequestHeader("content-type", "text/json")
2015-03-26 23:37:25 +03:00
if(!window.urb.oryx) throw "No CSRF token" // XX fetch auth.json
2015-03-20 01:21:14 +03:00
_data = {oryx: window.urb.oryx}
if(params.xyro) { _data.xyro = params.xyro; }
if(params.ship) { _data.ship = params.ship; }
if(params.path) { _data.path = params.path; }
if(params.appl) { _data.appl = params.appl; }
if(params.mark) { _data.mark = params.mark; }
2015-04-07 02:36:07 +03:00
if(params.wire) { _data.wire = params.wire; }
2015-03-20 01:21:14 +03:00
if(cb) {
xhr.onload = function() {
2015-11-03 02:31:48 +03:00
var err,res
2015-03-20 01:21:14 +03:00
try {
err = null
res = {
status:this.status,
data: JSON.parse(this.responseText)
}
if(res.data.reload)
res.reload = res.data.reload
} catch(e) {
2015-07-14 04:20:09 +03:00
// if(urb.wall !== false) document.write(this.responseText) // XX
2015-03-20 01:21:14 +03:00
err = {
message:"Failed to parse JSON",
raw:this.responseText
}
res = null
}
2015-11-03 02:31:48 +03:00
finally {
cb(err,res)
}
2015-03-20 01:21:14 +03:00
}
xhr.onerror = function() {
cb({
status:this.status,
data:this.responseText
})
}
}
xhr.send(JSON.stringify(_data))
}
2015-05-15 21:27:44 +03:00
// window.urb.getJSON = function(url,cb){ window.urb.reqJSON("GET",url, null, cb)}
// window.urb.reqJSON = function(method, url, data, cb){
// var xhr = new XMLHttpRequest()
// xhr.open(method, url)
// xhr.onload = function(){
// urb.fetchTag.call(xhr)
// if(cb) cb(JSON.parse(xhr.responseText))
// }
// xhr.send(data === null ? null : JSON.stringify(data))
// }
2015-03-20 01:21:14 +03:00
window.urb.reqq = []
window.urb.qreq = function(method,url,params,json,cb) {
walk = function() {
qobj = {}
qobj.oargs = window.urb.reqq[0]
2015-11-03 02:31:48 +03:00
qobj.nargs = [].slice.call(qobj.oargs,0,4)
2015-03-20 01:21:14 +03:00
qobj.nargs.push(function(){
if(this.oargs[4])
this.oargs[4].apply(window.urb,arguments)
window.urb.reqq.shift()
if(window.urb.reqq.length > 0)
walk()
}.bind(qobj))
window.urb.req.apply(this,qobj.nargs)
}
l = window.urb.reqq.length
window.urb.reqq.push(arguments);
if(l == 0) { walk() }
}
window.urb.send = function(data,params,cb) { // or send(data, cb)
2015-08-20 02:16:42 +03:00
if(!params || typeof params === "function")
{cb = params; params = {}}
2015-08-20 00:50:41 +03:00
var url, $send
$send = this.send
params.data = data
2015-08-20 00:50:41 +03:00
params.ship = params.ship || this.ship
params.appl = params.appl || this.appl
params.mark = params.mark || $send.mark
2015-11-03 02:31:48 +03:00
// params.seqn = params.seqn || $send.seqn
2015-08-20 00:50:41 +03:00
params.wire = params.wire || "/"
params.xyro = (typeof(params.data) === 'undefined') ? null : params.data
2015-08-20 00:50:41 +03:00
if(!params.mark) throw new Error("You must specify a mark for urb.send.")
if(!params.appl) throw new Error("You must specify an appl for urb.send.")
2015-08-20 00:50:41 +03:00
url = ["to",params.appl,params.mark]
url = "/~/"+url.join("/")
2015-11-03 02:31:48 +03:00
// $send.seqn++
2015-08-20 00:50:41 +03:00
this.qreq('post',url,params,true,function(err,data) {
2015-11-03 02:31:48 +03:00
/* if(err) { $send.seqn--; }
else */ if(data && data.data.fail && urb.wall !== false)
2015-08-20 00:50:41 +03:00
document.write("<pre>"+JSON.stringify(params.xyro)+"\n"
+data.data.mess+"</pre>") // XX
if(cb) { cb.apply(this,arguments); }
})
}
2015-11-03 02:31:48 +03:00
// window.urb.send.seqn = 0
2015-08-20 00:50:41 +03:00
window.urb.send.mark = "json"
2015-03-20 01:21:14 +03:00
window.urb.gsig = function(params) {
var path = params.path
if(!path) path = ""
2015-04-07 02:36:07 +03:00
if(path[0] !== "/") path = "/"+path
2015-03-20 02:35:10 +03:00
return "~"+params.ship+"/"+
2015-03-20 01:21:14 +03:00
params.appl+
path.replace(/[^\x00-\x7F]/g, "")
}
2015-08-20 00:50:41 +03:00
window.urb.puls = false
window.urb.cabs = {}
2015-03-20 02:35:10 +03:00
window.urb.poll = function(params) {
if(!params) throw new Error("You must supply params to urb.poll.")
2015-03-20 01:21:14 +03:00
2015-03-20 02:35:10 +03:00
var url, $this
2015-03-20 01:21:14 +03:00
2015-08-20 00:50:41 +03:00
seqn = this.poll.seqn
2015-03-20 02:35:10 +03:00
if(params.seqn) seqn = params.seqn()
2015-03-20 01:21:14 +03:00
2015-03-20 02:35:10 +03:00
url = "/~/of/"+this.ixor+"?poll="+seqn
2015-03-20 01:21:14 +03:00
2015-03-20 02:35:10 +03:00
this.puls = true
2015-03-20 01:21:14 +03:00
$this = this
this.req("get",url,params,true,function(err,res) {
2015-11-03 02:31:48 +03:00
$this.poll.dely = params.dely || $this.poll.dely
if(res){
if(res.data.beat)
2015-03-20 02:35:10 +03:00
return $this.poll(params)
switch(res.data.type){
2015-03-20 02:35:10 +03:00
case "news":
return document.location.reload() // XX check autoreload
case "rush":
2015-03-27 04:01:28 +03:00
case "mean":
2015-04-08 21:46:05 +03:00
var err2 = err
2015-04-07 23:36:33 +03:00
if(res.data.type == "mean")
2015-04-08 21:46:05 +03:00
err2 = res.data.data
var fn = $this.gsig(res.data.from)
2015-03-20 02:35:10 +03:00
if($this.cabs[fn])
2015-04-08 21:46:05 +03:00
$this.cabs[fn].call(this,err2,
{status: res.status, data: res.data.data.json}) // XX non-json
2015-03-20 02:35:10 +03:00
break;
default:
2015-03-27 04:01:28 +03:00
throw new Error("Lost event %"+res.data.type)
2015-03-20 01:21:14 +03:00
}
if(params.incs)
params.incs()
2015-03-20 02:35:10 +03:00
else
2015-08-20 00:50:41 +03:00
$this.poll.seqn++
2015-11-03 02:31:48 +03:00
$this.poll.dely = 250
return $this.poll(params)
2015-03-20 01:21:14 +03:00
}
2015-11-03 02:31:48 +03:00
else if(err){
setTimeout(function() {
$this.poll(params)
}, $this.poll.dely)
$this.poll.dely += Math.ceil($this.poll.dely*.2)
}
else throw "Neither error nor result on poll"
2015-03-20 01:21:14 +03:00
})
}
2015-08-20 00:50:41 +03:00
window.urb.poll.seqn = 1
2015-11-03 02:31:48 +03:00
window.urb.poll.dely = 250
2015-03-20 01:21:14 +03:00
window.urb.bind = function(path, params, cb, nicecb){ // or bind(path, cb)
2015-08-20 02:16:42 +03:00
if(!params || typeof params === "function")
{cb = params; params = {}}
params.path = path
2015-04-07 02:36:07 +03:00
if(params.path[0] !== "/") params.path = "/"+params.path
params.ship = params.ship || this.ship
params.appl = params.appl || this.appl
2015-08-20 20:37:22 +03:00
params.mark = params.mark || this.bind.mark
params.wire = params.wire || params.path
2015-04-07 02:36:07 +03:00
if(typeof path != "string")
throw new Error("You must specify a string path for urb.bind.")
2015-03-20 02:35:10 +03:00
if(!params.appl) throw new Error("You must specify an appl for urb.bind.")
if(!cb) throw new Error("You must supply a callback to urb.bind.")
2014-08-01 03:57:35 +04:00
var method, perm, url, $this
2015-03-27 01:32:32 +03:00
if(params.mark !== "json")
throw new Error("Non-json subscriptions unimplemented.") // XX
url = "/~/is/"+this.gsig(params)+"."+params.mark
2015-04-07 02:36:07 +03:00
params.path = params.wire
this.cabs[this.gsig(params)] = cb
2014-08-01 03:57:35 +04:00
$this = this
this.qreq("put",url,params,true,function(err,res) {
if(nicecb) { nicecb.apply(this,[err,{status: res.status, data: res.data}])}
2015-03-20 02:35:10 +03:00
// XX give raw data
//
if(!err && !$this.puls) $this.poll(params)
2014-08-01 03:57:35 +04:00
})
2014-07-17 06:10:13 +04:00
}
2015-08-20 20:37:22 +03:00
urb.bind.mark = "json"
window.urb.drop = function(path, params, cb){ // or drop(path,cb)
if(typeof params === "function")
{cb = params; params = {}}
params.path = path
if(params.path[0] !== "/") params.path = "/"+params.path
params.ship = params.ship || this.ship
params.appl = params.appl || this.appl
params.wire = params.wire || params.path
2014-08-01 03:57:35 +04:00
if(typeof path != "string")
throw new Error("You must specify a string path for urb.drop.")
if(!params.appl) throw new Error("You must specify an appl for urb.drop.")
2015-03-27 02:29:17 +03:00
2015-04-11 01:45:17 +03:00
url = "/~/is/"+this.gsig(params)+".json"
2015-03-27 02:29:17 +03:00
method = "delete"
this.req("delete",url,params,true,function(err,res) {
2015-05-15 00:59:45 +03:00
if(cb) cb(err,res)
2014-08-01 03:57:35 +04:00
})
}
2014-12-10 02:51:18 +03:00
window.urb.subscribe = function(params,cb) { // legacy interface
if(!params) throw new Error("You must supply params to urb.subscribe")
return window.urb.bind(params.path, params, cb, cb)
}
window.urb.unsubscribe = function(params,cb) { // legacy intreface
if(!params) throw new Error("You must supply params to urb.unsubscribe.")
return window.urb.drop(params.path, params, cb)
}
2014-12-10 02:51:18 +03:00
window.urb.util = {
isURL: function(s) {
r = new RegExp('^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i');
return s.length < 2083 && r.test(s);
},
2015-04-10 20:55:07 +03:00
numDot: function(n) {
_n = String(n)
fun = function(s){
if(s.length <= 3)
return s
return fun(s.slice(0,-3))+"."+s.slice(-3)
}
return fun((_n))
2015-04-10 20:55:07 +03:00
},
2014-12-10 02:51:18 +03:00
toDate: function (dat){
var mils = Math.floor((0x10000 * dat.getUTCMilliseconds()) / 1000).toString(16)
2015-01-09 22:57:15 +03:00
function pad(num, str){
return ((new Array(num + 1)).join('0') + str).substr(-num,num)
}
2014-12-10 02:51:18 +03:00
return '~' + dat.getUTCFullYear() +
'.' + (dat.getUTCMonth() + 1) +
'.' + dat.getUTCDate() +
2015-01-09 22:57:15 +03:00
'..' + pad(2, dat.getUTCHours()) +
'.' + pad(2, dat.getUTCMinutes()) +
'.' + pad(2, dat.getUTCSeconds()) +
'..' + pad(4, mils)
},
basepath: function(spur, pathname){
spur = spur || ''
2015-10-21 00:31:09 +03:00
if(spur === '/') spur = ''
pathname = pathname || window.location.pathname
if(pathname[0] == '/') pathname = pathname.slice(1)
2015-12-08 00:36:13 +03:00
if(pathname[0] != '~' && pathname[0] != '='){
return spur
}
pathname = pathname.split("/")
var pref, pred, prec, base = ""
while(base += "/"+(pref = pathname.shift()), pathname.length>0){
if(pref[0] !== '~') break;
if(pref === "~~") continue;
base += "/"+(pred = pathname.shift())
if(/[a-z\-]+/.test(pref.slice(1))){
base += "/"+(prec = pathname.shift())
if(prec == null) throw "Bad basepath."
break;
}
if(pref !== "~") throw "Bad basepath /"+pref
if(pred === "as"){
base += "/"+(prec = pathname.shift())
if(prec == null) throw "Bad basepath."
continue;
}
throw "Bad basepath /~/"+pred
}
return base+spur
2014-12-10 02:51:18 +03:00
}
}