blob: f9b4bb20c610e55d436abc77e85769d03cea7227 [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
API = 2
Number.prototype.pad = (n) ->
str = String(this)
# Do we need to pad? if so, do it using String.repeat
if (str.length < n)
str = "0".repeat(n - str.length) + str;
return str
Number.prototype.pretty = (fix) ->
if (fix)
return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,');
fetch = (url, xstate, callback, nocreds) ->
xmlHttp = null;
# Set up request object
if window.XMLHttpRequest
xmlHttp = new XMLHttpRequest();
else
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
if not nocreds
xmlHttp.withCredentials = true
# GET URL
xmlHttp.open("GET", "api/#{url}", true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = (state) ->
if xmlHttp.readyState == 4 and xmlHttp.status == 500
if snap
snap(xstate)
return
if xmlHttp.readyState == 4 and xmlHttp.status >= 400
js = JSON.parse(xmlHttp.responseText)
# If we need to log in first, redirect to login page
if js.code == 403
mpart = location.href.match(/\/\/[^/]+\/(.+)$/)[1]
location.href = "login.html?redirect=" + mpart
badModal(js.reason)
return
if xmlHttp.readyState == 4 and xmlHttp.status == 200
if callback
# Try to parse as JSON and deal with cache objects, fall back to old style parse-and-pass
try
response = JSON.parse(xmlHttp.responseText)
callback(response, xstate);
catch e
callback(JSON.parse(xmlHttp.responseText), xstate)
put = (url, json, xstate, callback, nocreds = false) ->
xmlHttp = null;
# Set up request object
if window.XMLHttpRequest
xmlHttp = new XMLHttpRequest();
else
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
if not nocreds
xmlHttp.withCredentials = true
# GET URL
xmlHttp.open("PUT", "api/#{url}", true);
xmlHttp.send(JSON.stringify(json || {}));
xmlHttp.onreadystatechange = (state) ->
if xmlHttp.readyState == 4 and xmlHttp.status == 500
if snap
snap(xstate)
return
if xmlHttp.readyState == 4 and xmlHttp.status >= 400
js = JSON.parse(xmlHttp.responseText)
badModal(js.reason)
return
if xmlHttp.readyState == 4 and xmlHttp.status == 200
if callback
# Try to parse as JSON and deal with cache objects, fall back to old style parse-and-pass
try
response = JSON.parse(xmlHttp.responseText)
if response && response.loginRequired
location.href = "/login.html"
return
callback(response, xstate);
catch e
callback(JSON.parse(xmlHttp.responseText), xstate)
patch = (url, json, xstate, callback, nocreds = false) ->
xmlHttp = null;
# Set up request object
if window.XMLHttpRequest
xmlHttp = new XMLHttpRequest();
else
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
if not nocreds
xmlHttp.withCredentials = true
# GET URL
xmlHttp.open("PATCH", "api/#{url}", true);
xmlHttp.send(JSON.stringify(json || {}));
xmlHttp.onreadystatechange = (state) ->
if xmlHttp.readyState == 4 and xmlHttp.status == 500
if snap
snap(xstate)
return
if xmlHttp.readyState == 4 and xmlHttp.status >= 400
js = JSON.parse(xmlHttp.responseText)
badModal(js.reason)
return
if xmlHttp.readyState == 4 and xmlHttp.status == 200
if callback
# Try to parse as JSON and deal with cache objects, fall back to old style parse-and-pass
try
response = JSON.parse(xmlHttp.responseText)
if response && response.loginRequired
location.href = "/login.html"
return
callback(response, xstate);
catch e
callback(JSON.parse(xmlHttp.responseText), xstate)
xdelete = (url, json, xstate, callback, nocreds = false) ->
xmlHttp = null;
# Set up request object
if window.XMLHttpRequest
xmlHttp = new XMLHttpRequest();
else
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
if not nocreds
xmlHttp.withCredentials = true
# GET URL
xmlHttp.open("DELETE", "api/#{url}", true);
xmlHttp.send(JSON.stringify(json || {}));
xmlHttp.onreadystatechange = (state) ->
if xmlHttp.readyState == 4 and xmlHttp.status == 500
if snap
snap(xstate)
return
if xmlHttp.readyState == 4 and xmlHttp.status >= 400
js = JSON.parse(xmlHttp.responseText)
badModal(js.reason)
return
if xmlHttp.readyState == 4 and xmlHttp.status == 200
if callback
# Try to parse as JSON and deal with cache objects, fall back to old style parse-and-pass
try
response = JSON.parse(xmlHttp.responseText)
if response && response.loginRequired
location.href = "/login.html"
return
callback(response, xstate);
catch e
callback(JSON.parse(xmlHttp.responseText), xstate)
post = (url, json, xstate, callback, snap) ->
xmlHttp = null;
# Set up request object
if window.XMLHttpRequest
xmlHttp = new XMLHttpRequest();
else
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlHttp.withCredentials = true
# Construct form data
for key, val of json
if val.match
if val.match(/^\d+$/)
json[key] = parseInt(val)
if val == 'true'
json[key] = true
if val == 'false'
json[key] = false
fdata = JSON.stringify(json)
# POST URL
xmlHttp.open("POST", "api/#{url}", true);
xmlHttp.setRequestHeader("Content-type", "application/json");
xmlHttp.send(fdata);
xmlHttp.onreadystatechange = (state) ->
if xmlHttp.readyState == 4 and xmlHttp.status == 500
if snap
snap(xstate)
if xmlHttp.readyState == 4 and xmlHttp.status == 200
if callback
# Try to parse as JSON and deal with cache objects, fall back to old style parse-and-pass
try
response = JSON.parse(xmlHttp.responseText)
if xstate and xstate.widget
xstate.widget.json = response
callback(response, xstate);
catch e
callback(JSON.parse(xmlHttp.responseText), xstate)
mk = (t, s, tt) ->
r = document.createElement(t)
if s
for k, v of s
if v
r.setAttribute(k, v)
if tt
if typeof tt == "string"
app(r, txt(tt))
else
if isArray tt
for k in tt
if typeof k == "string"
app(r, txt(k))
else
app(r, k)
else
app(r, tt)
return r
app = (a,b) ->
if isArray b
for item in b
if typeof item == "string"
item = txt(item)
a.appendChild(item)
else
return a.appendChild(b)
set = (a, b, c) ->
return a.setAttribute(b,c)
txt = (a) ->
return document.createTextNode(a)
get = (a) ->
return document.getElementById(a)
swi = (obj) ->
switchery = new Switchery(obj, {
color: '#26B99A'
})
cog = (div, size = 200) ->
idiv = document.createElement('div')
idiv.setAttribute("class", "icon")
idiv.setAttribute("style", "text-align: center; vertical-align: middle; height: 500px;")
i = document.createElement('i')
i.setAttribute("class", "fa fa-spin fa-cog")
i.setAttribute("style", "font-size: " + size + "pt !important; color: #AAB;")
idiv.appendChild(i)
idiv.appendChild(document.createElement('br'))
idiv.appendChild(document.createTextNode('Loading, hang on tight..!'))
div.innerHTML = ""
div.appendChild(idiv)
globArgs = {}
theme = {
color: [],
title: {
itemGap: 8,
textStyle: {
fontWeight: 'normal',
color: '#408829'
}
},
dataRange: {
color: ['#1f610a', '#97b58d']
},
toolbox: {
color: ['#408829', '#408829', '#408829', '#408829']
},
tooltip: {
backgroundColor: 'rgba(0,0,0,0.5)',
axisPointer: {
type: 'line',
lineStyle: {
color: '#408829',
type: 'dashed'
},
crossStyle: {
color: '#408829'
},
shadowStyle: {
color: 'rgba(200,200,200,0.3)'
}
}
},
dataZoom: {
dataBackgroundColor: '#eee',
fillerColor: 'rgba(64,136,41,0.2)',
handleColor: '#408829'
},
grid: {
borderWidth: 0
},
categoryAxis: {
axisLine: {
lineStyle: {
color: '#408829'
}
},
splitLine: {
lineStyle: {
color: ['#eee']
}
}
},
valueAxis: {
axisLine: {
lineStyle: {
color: '#408829'
}
},
splitArea: {
show: true,
areaStyle: {
color: ['rgba(250,250,250,0.1)', 'rgba(200,200,200,0.1)']
}
},
splitLine: {
lineStyle: {
color: ['#eee']
}
}
},
timeline: {
lineStyle: {
color: '#408829'
},
controlStyle: {
normal: {color: '#408829'},
emphasis: {color: '#408829'}
}
},
k: {
itemStyle: {
normal: {
color: '#68a54a',
color0: '#a9cba2',
lineStyle: {
width: 1,
color: '#408829',
color0: '#86b379'
}
}
}
},
map: {
itemStyle: {
normal: {
areaStyle: {
color: '#ddd'
},
label: {
textStyle: {
color: '#c12e34'
}
}
},
emphasis: {
areaStyle: {
color: '#99d2dd'
},
label: {
textStyle: {
color: '#c12e34'
}
}
}
}
},
force: {
itemStyle: {
normal: {
linkStyle: {
strokeColor: '#408829'
}
}
}
},
chord: {
padding: 4,
itemStyle: {
normal: {
lineStyle: {
width: 1,
color: 'rgba(128, 128, 128, 0.5)'
},
chordStyle: {
lineStyle: {
width: 1,
color: 'rgba(128, 128, 128, 0.5)'
}
}
},
emphasis: {
lineStyle: {
width: 1,
color: 'rgba(128, 128, 128, 0.5)'
},
chordStyle: {
lineStyle: {
width: 1,
color: 'rgba(128, 128, 128, 0.5)'
}
}
}
}
},
gauge: {
startAngle: 225,
endAngle: -45,
axisLine: {
show: true,
lineStyle: {
color: [[0.2, '#86b379'], [0.8, '#68a54a'], [1, '#408829']],
width: 8
}
},
axisTick: {
splitNumber: 10,
length: 12,
lineStyle: {
color: 'auto'
}
},
axisLabel: {
textStyle: {
color: 'auto'
}
},
splitLine: {
length: 18,
lineStyle: {
color: 'auto'
}
},
pointer: {
length: '90%',
color: 'auto'
},
title: {
textStyle: {
color: '#333'
}
},
detail: {
textStyle: {
color: 'auto'
}
}
},
textStyle: {
fontFamily: 'Arial, Verdana, sans-serif'
}
};
isArray = ( value ) ->
value and
typeof value is 'object' and
value instanceof Array and
typeof value.length is 'number' and
typeof value.splice is 'function' and
not ( value.propertyIsEnumerable 'length' )
### isHash: function to detect if an object is a hash ###
isHash = (value) ->
value and
typeof value is 'object' and
not isArray(value)
class HTML
constructor: (type, params, children) ->
### create the raw element, or clone if passed an existing element ###
if typeof type is 'object'
@element = type.cloneNode()
else
@element = document.createElement(type)
### If params have been passed, set them ###
if isHash(params)
for key, val of params
### Standard string value? ###
if typeof val is "string" or typeof val is 'number'
@element.setAttribute(key, val)
else if isArray(val)
### Are we passing a list of data to set? concatenate then ###
@element.setAttribute(key, val.join(" "))
else if isHash(val)
### Are we trying to set multiple sub elements, like a style? ###
for subkey,subval of val
if not @element[key]
throw "No such attribute, #{key}!"
@element[key][subkey] = subval
### If any children have been passed, add them to the element ###
if children
### If string, convert to textNode using txt() ###
if typeof children is "string"
@element.inject(txt(children))
else
### If children is an array of elems, iterate and add ###
if isArray children
for child in children
### String? Convert via txt() then ###
if typeof child is "string"
@element.inject(txt(child))
else
### Plain element, add normally ###
@element.inject(child)
else
### Just a single element, add it ###
@element.inject(children)
return @element
###*
# prototype injector for HTML elements:
# Example: mydiv.inject(otherdiv)
###
HTMLElement.prototype.inject = (child) ->
if isArray(child)
for item in child
# Convert to textNode if string
if typeof item is 'string'
item = txt(item)
this.appendChild(item)
else
# Convert to textNode if string
if typeof child is 'string'
child = txt(child)
this.appendChild(child)
return child
Date.prototype.ISOBare = () ->
y = this.getFullYear()
m = (this.getMonth() + 1).pad(2)
d = this.getDate().pad(2)
h = this.getHours().pad(2)
M = this.getMinutes().pad(2)
return y + "-" + m + "-" + d + " " + h + ":" + M